mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-01 15:03:11 +02:00
Database access refactor (#190)
This commit is contained in:
232
package-lock.json
generated
232
package-lock.json
generated
@@ -22,9 +22,9 @@
|
||||
"src-web"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
||||
"@typescript-eslint/parser": "^8.18.1",
|
||||
"@tauri-apps/cli": "^2.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
||||
"@typescript-eslint/parser": "^8.27.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-prettier": "^8",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
@@ -34,7 +34,7 @@
|
||||
"nodejs-file-downloader": "^4.13.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.4.2",
|
||||
"typescript": "^5.7.2"
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@@ -2782,9 +2782,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.2.7.tgz",
|
||||
"integrity": "sha512-ZnsS2B4BplwXP37celanNANiIy8TCYhvg5RT09n72uR/o+navFZtGpFSqljV8fy1Y4ixIPds8FrGSXJCN2BerA==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.4.0.tgz",
|
||||
"integrity": "sha512-Esg7s20tuSULd2YF3lmtMa1vF7yr5eh/TlBHXjEyrC+XSD9aBxHVoXb6oz7oKybDY9Jf9OiBa0bf2PbybcmOLA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"bin": {
|
||||
@@ -2798,22 +2798,23 @@
|
||||
"url": "https://opencollective.com/tauri"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tauri-apps/cli-darwin-arm64": "2.2.7",
|
||||
"@tauri-apps/cli-darwin-x64": "2.2.7",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.2.7",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.2.7",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.2.7",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.2.7",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.2.7",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.2.7",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.2.7",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.2.7"
|
||||
"@tauri-apps/cli-darwin-arm64": "2.4.0",
|
||||
"@tauri-apps/cli-darwin-x64": "2.4.0",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.4.0",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.4.0",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.4.0",
|
||||
"@tauri-apps/cli-linux-riscv64-gnu": "2.4.0",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.4.0",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.4.0",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.4.0",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.4.0",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.2.7.tgz",
|
||||
"integrity": "sha512-54kcpxZ3X1Rq+pPTzk3iIcjEVY4yv493uRx/80rLoAA95vAC0c//31Whz75UVddDjJfZvXlXZ3uSZ+bnCOnt0A==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.4.0.tgz",
|
||||
"integrity": "sha512-MVzYrahJBgDyzUJ2gNEU8H+0oCVEucN115+CVorFnidHcJ6DtDRMCaKLkpjOZNfJyag1WQ25fu7imvZSe0mz/g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2828,9 +2829,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.2.7.tgz",
|
||||
"integrity": "sha512-Vgu2XtBWemLnarB+6LqQeLanDlRj7CeFN//H8bVVdjbNzxcSxsvbLYMBP8+3boa7eBnjDrqMImRySSgL6IrwTw==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.4.0.tgz",
|
||||
"integrity": "sha512-/4IdbWv6IWSuBn0WVe5JkiSIP1gZhXCZRcumSsYq3ZmOlq4BqXeXT36Oig5mlDnS/2/UpNS94kd8gOA1DNdIeQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2845,9 +2846,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.2.7.tgz",
|
||||
"integrity": "sha512-+Clha2iQAiK9zoY/KKW0KLHkR0k36O78YLx5Sl98tWkwI3OBZFg5H5WT1plH/4sbZIS2aLFN6dw58/JlY9Bu/g==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.4.0.tgz",
|
||||
"integrity": "sha512-rOjlk3Vd6R847LXds4pOAFKUL5NVdSWlaiQvr4H9WDUwIWWoxnj7SQfpryTtElDb2wV7a0BNaOCXCpyFEAXjkw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2862,9 +2863,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.2.7.tgz",
|
||||
"integrity": "sha512-Z/Lp4SQe6BUEOays9BQAEum2pvZF4w9igyXijP+WbkOejZx4cDvarFJ5qXrqSLmBh7vxrdZcLwoLk9U//+yQrg==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.4.0.tgz",
|
||||
"integrity": "sha512-X/uCwao6R/weWT2y4f3JKJMeUsujo9H4nBMAv9RZhRsz93n9Amw9ETavAOP11pyhl57YkasvKTCRQN6FwsaoXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2879,9 +2880,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.7.tgz",
|
||||
"integrity": "sha512-+8HZ+txff/Y3YjAh80XcLXcX8kpGXVdr1P8AfjLHxHdS6QD4Md+acSxGTTNbplmHuBaSHJvuTvZf9tU1eDCTDg==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.0.tgz",
|
||||
"integrity": "sha512-GhvQtrTjadW3eLSmfrSfybSqgJMZzUXC+0WqDzFovLug3a1a1go0m9QK9YGvYLkyEpTY5zRxLtwv+tbZXN4tZw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2895,10 +2896,27 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-riscv64-gnu": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.4.0.tgz",
|
||||
"integrity": "sha512-NgeNihQ9uHS/ibMWLge5VA/BgsS/g8VPSVtCp8DSPyub3bBuCy79A8V+bzNKlMOiDVrqK4vQ//FS9kSxoJOtXw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.2.7.tgz",
|
||||
"integrity": "sha512-ahlSnuCnUntblp9dG7/w5ZWZOdzRFi3zl0oScgt7GF4KNAOEa7duADsxPA4/FT2hLRa0SvpqtD4IYFvCxoVv3Q==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.4.0.tgz",
|
||||
"integrity": "sha512-ebRmV2HLIVms1KlNNueQCp3OrXBv6cimU3mYEh5NbZ8dH88f2sF46dFCyPq8Qr/Zti4qPEaAArVG7RYFjfECPw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2913,9 +2931,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.7.tgz",
|
||||
"integrity": "sha512-+qKAWnJRSX+pjjRbKAQgTdFY8ecdcu8UdJ69i7wn3ZcRn2nMMzOO2LOMOTQV42B7/Q64D1pIpmZj9yblTMvadA==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.0.tgz",
|
||||
"integrity": "sha512-FOp2cBFyq5LnUr3he95Z99PQm3nCSJv2GZNeH7UqmUpeHwdcYuhBERU7C+8VDJJPR98Q5fkcoV00Pc4nw0v5KQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2930,9 +2948,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.2.7.tgz",
|
||||
"integrity": "sha512-aa86nRnrwT04u9D9fhf5JVssuAZlUCCc8AjqQjqODQjMd4BMA2+d4K9qBMpEG/1kVh95vZaNsLogjEaqSTTw4A==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.4.0.tgz",
|
||||
"integrity": "sha512-SVf1wDagYsaFM+mpUYKmjNveKodcUSGPEM27WmMW4Enh6aXGzTJi4IYOE3GEFOJF1BpRNscslwE1Rd064kfpcg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2947,9 +2965,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.2.7.tgz",
|
||||
"integrity": "sha512-EiJ5/25tLSQOSGvv+t6o3ZBfOTKB5S3vb+hHQuKbfmKdRF0XQu2YPdIi1CQw1DU97ZAE0Dq4frvnyYEKWgMzVQ==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.4.0.tgz",
|
||||
"integrity": "sha512-j+fOFVeSSejk9hrUePY7bJuaYr+80xr+ftjXzxCj0CS0d2oSbq+lT8/zS514WemJk9e9yxUus+2ke/Ng17wkkQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2964,9 +2982,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.2.7.tgz",
|
||||
"integrity": "sha512-ZB8Kw90j8Ld+9tCWyD2fWCYfIrzbQohJ4DJSidNwbnehlZzP7wAz6Z3xjsvUdKtQ3ibtfoeTqVInzCCEpI+pWg==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.4.0.tgz",
|
||||
"integrity": "sha512-nv84b3a8eI5Y7ksTLBKjjvtr9NOlAGGGo7OJbjKT+xZLdiPOZ0nJ2cT+4IdfnNAZ33pKJugAfuj1fBvQKeTy0w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3296,21 +3314,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz",
|
||||
"integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.27.0.tgz",
|
||||
"integrity": "sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.18.1",
|
||||
"@typescript-eslint/type-utils": "8.18.1",
|
||||
"@typescript-eslint/utils": "8.18.1",
|
||||
"@typescript-eslint/visitor-keys": "8.18.1",
|
||||
"@typescript-eslint/scope-manager": "8.27.0",
|
||||
"@typescript-eslint/type-utils": "8.27.0",
|
||||
"@typescript-eslint/utils": "8.27.0",
|
||||
"@typescript-eslint/visitor-keys": "8.27.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3322,20 +3340,20 @@
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz",
|
||||
"integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.27.0.tgz",
|
||||
"integrity": "sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.18.1",
|
||||
"@typescript-eslint/types": "8.18.1",
|
||||
"@typescript-eslint/typescript-estree": "8.18.1",
|
||||
"@typescript-eslint/visitor-keys": "8.18.1",
|
||||
"@typescript-eslint/scope-manager": "8.27.0",
|
||||
"@typescript-eslint/types": "8.27.0",
|
||||
"@typescript-eslint/typescript-estree": "8.27.0",
|
||||
"@typescript-eslint/visitor-keys": "8.27.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3347,18 +3365,18 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz",
|
||||
"integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.27.0.tgz",
|
||||
"integrity": "sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.18.1",
|
||||
"@typescript-eslint/visitor-keys": "8.18.1"
|
||||
"@typescript-eslint/types": "8.27.0",
|
||||
"@typescript-eslint/visitor-keys": "8.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3369,16 +3387,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz",
|
||||
"integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.27.0.tgz",
|
||||
"integrity": "sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.18.1",
|
||||
"@typescript-eslint/utils": "8.18.1",
|
||||
"@typescript-eslint/typescript-estree": "8.27.0",
|
||||
"@typescript-eslint/utils": "8.27.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3389,13 +3407,13 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz",
|
||||
"integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.27.0.tgz",
|
||||
"integrity": "sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3407,20 +3425,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz",
|
||||
"integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.27.0.tgz",
|
||||
"integrity": "sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.18.1",
|
||||
"@typescript-eslint/visitor-keys": "8.18.1",
|
||||
"@typescript-eslint/types": "8.27.0",
|
||||
"@typescript-eslint/visitor-keys": "8.27.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3430,20 +3448,20 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz",
|
||||
"integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.27.0.tgz",
|
||||
"integrity": "sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.18.1",
|
||||
"@typescript-eslint/types": "8.18.1",
|
||||
"@typescript-eslint/typescript-estree": "8.18.1"
|
||||
"@typescript-eslint/scope-manager": "8.27.0",
|
||||
"@typescript-eslint/types": "8.27.0",
|
||||
"@typescript-eslint/typescript-estree": "8.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -3454,17 +3472,17 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz",
|
||||
"integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==",
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.27.0.tgz",
|
||||
"integrity": "sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.18.1",
|
||||
"@typescript-eslint/types": "8.27.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -13842,16 +13860,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-easing": {
|
||||
@@ -14440,9 +14458,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -15562,9 +15580,7 @@
|
||||
"@types/node": "^22.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cpy-cli": "^5.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.6.2"
|
||||
"cpy-cli": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"packages/plugin-runtime/node_modules/ws": {
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
"tauri-before-dev": "npm run --workspaces --if-present dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.2.7",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
||||
"@typescript-eslint/parser": "^8.18.1",
|
||||
"@tauri-apps/cli": "^2.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.27.0",
|
||||
"@typescript-eslint/parser": "^8.27.0",
|
||||
"eslint": "^8",
|
||||
"eslint-config-prettier": "^8",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
@@ -48,6 +48,6 @@
|
||||
"nodejs-file-downloader": "^4.13.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^3.4.2",
|
||||
"typescript": "^5.7.2"
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
"@types/node": "^22.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cpy-cli": "^5.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.6.2"
|
||||
"cpy-cli": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ export class PluginHandle {
|
||||
bootRequest: this.bootRequest,
|
||||
};
|
||||
this.#instance = new PluginInstance(workerData, pluginToAppEvents);
|
||||
console.log('Created plugin worker for ', this.bootRequest.dir);
|
||||
}
|
||||
|
||||
sendToWorker(event: InternalEvent) {
|
||||
|
||||
468
src-tauri/Cargo.lock
generated
468
src-tauri/Cargo.lock
generated
@@ -543,6 +543,15 @@ dependencies = [
|
||||
"objc2 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037"
|
||||
dependencies = [
|
||||
"objc2 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
@@ -737,9 +746,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cargo_toml"
|
||||
version = "0.21.0"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472"
|
||||
checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
@@ -825,22 +834,6 @@ dependencies = [
|
||||
"error-code",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"block",
|
||||
"cocoa-foundation 0.1.2",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics 0.23.2",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.26.0"
|
||||
@@ -849,7 +842,7 @@ checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"cocoa-foundation 0.2.0",
|
||||
"cocoa-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics 0.24.0",
|
||||
"foreign-types 0.5.0",
|
||||
@@ -857,20 +850,6 @@ dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"block",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types 0.1.3",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.2.0"
|
||||
@@ -1252,34 +1231,13 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.4.5",
|
||||
"windows-sys 0.48.0",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1290,7 +1248,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.0",
|
||||
"redox_users",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -2436,9 +2394,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ico"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae"
|
||||
checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"png",
|
||||
@@ -3031,21 +2989,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.15.1"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8123dfd4996055ac9b15a60ad263b44b01e539007523ad7a4a533a3d93b0591"
|
||||
checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"keyboard-types",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"once_cell",
|
||||
"png",
|
||||
"serde",
|
||||
"thiserror 1.0.63",
|
||||
"thiserror 2.0.11",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -3289,9 +3248,6 @@ name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
@@ -3310,6 +3266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59"
|
||||
dependencies = [
|
||||
"objc2-encode",
|
||||
"objc2-exception-helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3322,10 +3279,10 @@ dependencies = [
|
||||
"block2 0.5.1",
|
||||
"libc",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-core-data 0.2.2",
|
||||
"objc2-core-image 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-quartz-core",
|
||||
"objc2-quartz-core 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3335,32 +3292,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.6.0",
|
||||
"libc",
|
||||
"objc2 0.6.0",
|
||||
"objc2-cloud-kit",
|
||||
"objc2-core-data 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-core-image 0.3.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-quartz-core 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-cloud-kit"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
|
||||
checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-contacts"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
||||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3375,6 +3327,17 @@ dependencies = [
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-data"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.0"
|
||||
@@ -3385,6 +3348,18 @@ dependencies = [
|
||||
"objc2 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-graphics"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-surface",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-image"
|
||||
version = "0.2.2"
|
||||
@@ -3398,15 +3373,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-location"
|
||||
version = "0.2.2"
|
||||
name = "objc2-core-image"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
|
||||
checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56"
|
||||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-contacts",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3415,6 +3388,15 @@ version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-exception-helper"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.2.2"
|
||||
@@ -3435,20 +3417,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.6.0",
|
||||
"libc",
|
||||
"objc2 0.6.0",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-link-presentation"
|
||||
version = "0.2.2"
|
||||
name = "objc2-io-surface"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
||||
checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19"
|
||||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"bitflags 2.6.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3489,71 +3472,40 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-symbols"
|
||||
version = "0.2.2"
|
||||
name = "objc2-quartz-core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
|
||||
checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071"
|
||||
dependencies = [
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"bitflags 2.6.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-ui-kit"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
|
||||
checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-cloud-kit",
|
||||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-link-presentation",
|
||||
"objc2-quartz-core",
|
||||
"objc2-symbols",
|
||||
"objc2-uniform-type-identifiers",
|
||||
"objc2-user-notifications",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-uniform-type-identifiers"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
||||
dependencies = [
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-user-notifications"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-web-kit"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
|
||||
checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2 0.5.1",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"block2 0.6.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3567,9 +3519,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
@@ -4459,17 +4411,6 @@ dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 1.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
@@ -4483,9 +4424,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -5291,7 +5232,7 @@ dependencies = [
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2-quartz-core",
|
||||
"objc2-quartz-core 0.2.2",
|
||||
"raw-window-handle",
|
||||
"redox_syscall 0.5.3",
|
||||
"wasm-bindgen",
|
||||
@@ -5708,12 +5649,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.31.1"
|
||||
version = "0.32.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3731d04d4ac210cd5f344087733943b9bfb1a32654387dad4d1c70de21aee2c9"
|
||||
checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cocoa 0.26.0",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics 0.24.0",
|
||||
"crossbeam-channel",
|
||||
@@ -5730,7 +5670,9 @@ dependencies = [
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"ndk-sys",
|
||||
"objc",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"raw-window-handle",
|
||||
@@ -5738,8 +5680,8 @@ dependencies = [
|
||||
"tao-macros",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
@@ -5780,13 +5722,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.2.5"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58a998b6be84104ca05c7e9a21f2180ddec020c8b84ea59a8fc8530a2a19588d"
|
||||
checksum = "511dd38065a5d3b36c33cdba4362b99a40a5103bebcd4aebb930717e7c8ba292"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"dirs 6.0.0",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"embed_plist",
|
||||
"futures-util",
|
||||
@@ -5801,9 +5743,9 @@ dependencies = [
|
||||
"log",
|
||||
"mime",
|
||||
"muda",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
@@ -5826,18 +5768,18 @@ dependencies = [
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"window-vibrancy",
|
||||
"windows 0.58.0",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.0.6"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51a2e96f3c0baa0581656bb58e6fdd0f7c9c31eaf6721a0c08689d938fe85f2d"
|
||||
checksum = "7ffa8732a66f90903f5a585215f3cf1e87988d0359bc88c18a502efe7572c1de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
"dirs 6.0.0",
|
||||
"dirs",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"json-patch",
|
||||
@@ -5853,9 +5795,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.0.4"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f77894f9ddb5cb6c04fcfe8c8869ebe0aded4dabf19917118d48be4a95599ab5"
|
||||
checksum = "c266a247f14d63f40c6282c2653a8bac5cc3d482ca562a003a88513653ea817a"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli 7.0.0",
|
||||
@@ -5880,9 +5822,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.0.4"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3240a5caed760a532e8f687be6f05b2c7d11a1d791fb53ccc08cfeb3e5308736"
|
||||
checksum = "f47a1cf94b3bd6c4dc37dce1a43fc96120ff29a91757f0ab3cf713c7ad846e7c"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -5894,9 +5836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.0.4"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5841b9a0200e954ef7457f8d327091424328891e267a97b641dc246cc54d0dec"
|
||||
checksum = "9972871fcbddf16618f70412d965d4d845cd4b76d03fff168709961ef71e5cdf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@@ -6005,7 +5947,7 @@ dependencies = [
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.11",
|
||||
"url",
|
||||
"windows 0.60.0",
|
||||
"windows",
|
||||
"zbus 5.3.0",
|
||||
]
|
||||
|
||||
@@ -6070,7 +6012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31bfcfb4a8318008d2108ccfba439d8263cf48867baabf372cb0e9f24771896"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"dirs 6.0.0",
|
||||
"dirs",
|
||||
"flate2",
|
||||
"futures-util",
|
||||
"http",
|
||||
@@ -6112,10 +6054,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.3.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2274ef891ccc0a8d318deffa9d70053f947664d12d58b9c0d1ae5e89237e01f7"
|
||||
checksum = "9e9c7bce5153f1ca7bc45eba37349b31ba50e975e28edc8b5766c5ec02b0b63a"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"http",
|
||||
@@ -6126,22 +6069,23 @@ dependencies = [
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.11",
|
||||
"url",
|
||||
"windows 0.58.0",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.3.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3707b40711d3b9f6519150869e358ffbde7c57567fb9b5a8b51150606939b2a0"
|
||||
checksum = "087188020fd6facb8578fe9b38e81fa0fe5fb85744c73da51a299f94a530a1e3"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
"jni",
|
||||
"log",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-foundation 0.3.0",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"softbuffer",
|
||||
@@ -6151,16 +6095,17 @@ dependencies = [
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"windows 0.58.0",
|
||||
"windows",
|
||||
"wry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "107a959dbd5ff53d89a98f6f2e3e987c611334141a43630caae1d80e79446dd6"
|
||||
checksum = "82dcced4014e59af9790cc22f5d271df3be09ecd6728ec68861642553c8d01b7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"brotli 7.0.0",
|
||||
"cargo_metadata",
|
||||
"ctor",
|
||||
@@ -6610,22 +6555,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "533fc2d4105e0e3d96ce1c71f2d308c9fbbe2ef9c587cab63dd627ab5bde218f"
|
||||
checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5"
|
||||
dependencies = [
|
||||
"core-graphics 0.24.0",
|
||||
"crossbeam-channel",
|
||||
"dirs 5.0.1",
|
||||
"dirs",
|
||||
"libappindicator",
|
||||
"muda",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation 0.3.0",
|
||||
"once_cell",
|
||||
"png",
|
||||
"serde",
|
||||
"thiserror 1.0.63",
|
||||
"thiserror 2.0.11",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -7198,16 +7144,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.34.0"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "823e7ebcfaea51e78f72c87fc3b65a1e602c321f407a0b36dbb327d7bb7cd921"
|
||||
checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3"
|
||||
dependencies = [
|
||||
"webview2-com-macros",
|
||||
"webview2-com-sys",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
"windows-implement 0.58.0",
|
||||
"windows-interface 0.58.0",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7223,13 +7169,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com-sys"
|
||||
version = "0.34.0"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a82bce72db6e5ee83c68b5de1e2cd6ea195b9fbff91cb37df5884cbe3222df4"
|
||||
checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac"
|
||||
dependencies = [
|
||||
"thiserror 1.0.63",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
"thiserror 2.0.11",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7281,27 +7227,19 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "window-vibrancy"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33082acd404763b315866e14a0d5193f3422c81086657583937a750cdd3ec340"
|
||||
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
|
||||
dependencies = [
|
||||
"cocoa 0.25.0",
|
||||
"objc",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"raw-window-handle",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
dependencies = [
|
||||
"windows-core 0.58.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.60.0"
|
||||
@@ -7333,27 +7271,14 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement 0.58.0",
|
||||
"windows-interface 0.58.0",
|
||||
"windows-result 0.2.0",
|
||||
"windows-strings 0.1.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.60.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247"
|
||||
dependencies = [
|
||||
"windows-implement 0.59.0",
|
||||
"windows-interface 0.59.1",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-strings 0.3.1",
|
||||
@@ -7369,17 +7294,6 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.59.0"
|
||||
@@ -7391,17 +7305,6 @@ dependencies = [
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
@@ -7759,12 +7662,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.48.0"
|
||||
version = "0.50.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e644bf458e27b11b0ecafc9e5633d1304fdae82baca1d42185669752fe6ca4f"
|
||||
checksum = "b19b78efae8b853c6c817e8752fc1dbf9cab8a8ffe9c30f399bd750ccf0f0730"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.5.1",
|
||||
"block2 0.6.0",
|
||||
"cookie",
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
@@ -7778,9 +7681,10 @@ dependencies = [
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"ndk",
|
||||
"objc2 0.5.2",
|
||||
"objc2-app-kit 0.2.2",
|
||||
"objc2-foundation 0.2.2",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit 0.3.0",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"once_cell",
|
||||
@@ -7794,8 +7698,8 @@ dependencies = [
|
||||
"webkit2gtk",
|
||||
"webkit2gtk-sys",
|
||||
"webview2-com",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
"windows",
|
||||
"windows-core 0.60.1",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
@@ -7873,7 +7777,7 @@ name = "yaak-app"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"cocoa 0.26.0",
|
||||
"cocoa",
|
||||
"encoding_rs",
|
||||
"eventsource-client",
|
||||
"hex_color",
|
||||
@@ -8006,7 +7910,9 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ strip = true # Automatically strip symbols from the binary.
|
||||
cargo-clippy = []
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.6", features = [] }
|
||||
tauri-build = { version = "2.1.0", features = [] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
objc = "0.2.7"
|
||||
@@ -87,8 +87,8 @@ yaak-ws = { path = "yaak-ws" }
|
||||
reqwest = "0.12.12"
|
||||
serde = "1.0.215"
|
||||
serde_json = "1.0.132"
|
||||
tauri = "2.2.5"
|
||||
tauri-plugin = "2.0.4"
|
||||
tauri = "2.4.0"
|
||||
tauri-plugin = "2.1.0"
|
||||
tauri-plugin-shell = "2.2.0"
|
||||
thiserror = "2.0.3"
|
||||
ts-rs = "10.0.0"
|
||||
|
||||
2
src-tauri/gen/schemas/acl-manifests.json
generated
2
src-tauri/gen/schemas/acl-manifests.json
generated
File diff suppressed because one or more lines are too long
91
src-tauri/gen/schemas/desktop-schema.json
generated
91
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' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its 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",
|
||||
@@ -70,14 +70,14 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"windows": {
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`",
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"webviews": {
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -2137,11 +2137,26 @@
|
||||
"type": "string",
|
||||
"const": "core:app:allow-default-window-icon"
|
||||
},
|
||||
{
|
||||
"description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-fetch-data-store-identifiers"
|
||||
},
|
||||
{
|
||||
"description": "Enables the identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-identifier"
|
||||
},
|
||||
{
|
||||
"description": "Enables the name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-name"
|
||||
},
|
||||
{
|
||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-remove-data-store"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2172,11 +2187,26 @@
|
||||
"type": "string",
|
||||
"const": "core:app:deny-default-window-icon"
|
||||
},
|
||||
{
|
||||
"description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-fetch-data-store-identifiers"
|
||||
},
|
||||
{
|
||||
"description": "Denies the identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-identifier"
|
||||
},
|
||||
{
|
||||
"description": "Denies the name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-name"
|
||||
},
|
||||
{
|
||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-remove-data-store"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2972,6 +3002,11 @@
|
||||
"type": "string",
|
||||
"const": "core:window:allow-internal-toggle-maximize"
|
||||
},
|
||||
{
|
||||
"description": "Enables the is_always_on_top command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-is-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Enables the is_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -3337,6 +3372,11 @@
|
||||
"type": "string",
|
||||
"const": "core:window:deny-internal-toggle-maximize"
|
||||
},
|
||||
{
|
||||
"description": "Denies the is_always_on_top command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-is-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Denies the is_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5592,6 +5632,51 @@
|
||||
"type": "string",
|
||||
"const": "yaak-license:deny-deactivate"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
"const": "yaak-models:default"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
|
||||
91
src-tauri/gen/schemas/macOS-schema.json
generated
91
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' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its 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",
|
||||
@@ -70,14 +70,14 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"windows": {
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`",
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"webviews": {
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -2137,11 +2137,26 @@
|
||||
"type": "string",
|
||||
"const": "core:app:allow-default-window-icon"
|
||||
},
|
||||
{
|
||||
"description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-fetch-data-store-identifiers"
|
||||
},
|
||||
{
|
||||
"description": "Enables the identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-identifier"
|
||||
},
|
||||
{
|
||||
"description": "Enables the name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-name"
|
||||
},
|
||||
{
|
||||
"description": "Enables the remove_data_store command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:allow-remove-data-store"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_app_theme command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2172,11 +2187,26 @@
|
||||
"type": "string",
|
||||
"const": "core:app:deny-default-window-icon"
|
||||
},
|
||||
{
|
||||
"description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-fetch-data-store-identifiers"
|
||||
},
|
||||
{
|
||||
"description": "Denies the identifier command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-identifier"
|
||||
},
|
||||
{
|
||||
"description": "Denies the name command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-name"
|
||||
},
|
||||
{
|
||||
"description": "Denies the remove_data_store command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:app:deny-remove-data-store"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_app_theme command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2972,6 +3002,11 @@
|
||||
"type": "string",
|
||||
"const": "core:window:allow-internal-toggle-maximize"
|
||||
},
|
||||
{
|
||||
"description": "Enables the is_always_on_top command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-is-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Enables the is_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -3337,6 +3372,11 @@
|
||||
"type": "string",
|
||||
"const": "core:window:deny-internal-toggle-maximize"
|
||||
},
|
||||
{
|
||||
"description": "Denies the is_always_on_top command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-is-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Denies the is_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5592,6 +5632,51 @@
|
||||
"type": "string",
|
||||
"const": "yaak-license:deny-deactivate"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
"const": "yaak-models:default"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-models:deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
|
||||
@@ -3,27 +3,30 @@ use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Render error: {0}")]
|
||||
#[error(transparent)]
|
||||
TemplateError(#[from] yaak_templates::error::Error),
|
||||
|
||||
#[error("Model error: {0}")]
|
||||
#[error(transparent)]
|
||||
ModelError(#[from] yaak_models::error::Error),
|
||||
|
||||
#[error("Sync error: {0}")]
|
||||
#[error(transparent)]
|
||||
SyncError(#[from] yaak_sync::error::Error),
|
||||
|
||||
#[error("Git error: {0}")]
|
||||
#[error(transparent)]
|
||||
GitError(#[from] yaak_git::error::Error),
|
||||
|
||||
#[error("Websocket error: {0}")]
|
||||
#[error(transparent)]
|
||||
WebsocketError(#[from] yaak_ws::error::Error),
|
||||
|
||||
#[error("License error: {0}")]
|
||||
#[error(transparent)]
|
||||
LicenseError(#[from] yaak_license::error::Error),
|
||||
|
||||
#[error("Plugin error: {0}")]
|
||||
#[error(transparent)]
|
||||
PluginError(#[from] yaak_plugins::error::Error),
|
||||
|
||||
#[error("Updater error: {0}")]
|
||||
UpdaterError(#[from] tauri_plugin_updater::Error),
|
||||
|
||||
#[error("Request error: {0}")]
|
||||
RequestError(#[from] reqwest::Error),
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use tauri::{AppHandle, Runtime};
|
||||
|
||||
use yaak_models::queries::{
|
||||
get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string, UpdateSource,
|
||||
};
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
|
||||
const NAMESPACE: &str = "analytics";
|
||||
const NUM_LAUNCHES_KEY: &str = "num_launches";
|
||||
@@ -21,34 +19,28 @@ pub async fn store_launch_history<R: Runtime>(app_handle: &AppHandle<R>) -> Laun
|
||||
let mut info = LaunchEventInfo::default();
|
||||
|
||||
info.num_launches = get_num_launches(app_handle).await + 1;
|
||||
info.previous_version =
|
||||
get_key_value_string(app_handle, NAMESPACE, last_tracked_version_key, "").await;
|
||||
info.current_version = app_handle.package_info().version.to_string();
|
||||
|
||||
if info.previous_version.is_empty() {
|
||||
} else {
|
||||
info.launched_after_update = info.current_version != info.previous_version;
|
||||
};
|
||||
app_handle
|
||||
.queries()
|
||||
.with_tx(|tx| {
|
||||
info.previous_version =
|
||||
tx.get_key_value_string(NAMESPACE, last_tracked_version_key, "");
|
||||
|
||||
// Update key values
|
||||
if !info.previous_version.is_empty() {
|
||||
info.launched_after_update = info.current_version != info.previous_version;
|
||||
};
|
||||
|
||||
set_key_value_string(
|
||||
app_handle,
|
||||
NAMESPACE,
|
||||
last_tracked_version_key,
|
||||
info.current_version.as_str(),
|
||||
&UpdateSource::Background,
|
||||
)
|
||||
.await;
|
||||
// Update key values
|
||||
|
||||
set_key_value_int(
|
||||
app_handle,
|
||||
NAMESPACE,
|
||||
NUM_LAUNCHES_KEY,
|
||||
info.num_launches,
|
||||
&UpdateSource::Background,
|
||||
)
|
||||
.await;
|
||||
let source = &UpdateSource::Background;
|
||||
let version = info.current_version.as_str();
|
||||
tx.set_key_value_string(NAMESPACE, last_tracked_version_key, version, source);
|
||||
tx.set_key_value_int(NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches, source);
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
info
|
||||
}
|
||||
@@ -66,5 +58,5 @@ pub fn get_os() -> &'static str {
|
||||
}
|
||||
|
||||
pub async fn get_num_launches<R: Runtime>(app_handle: &AppHandle<R>) -> i32 {
|
||||
get_key_value_int(app_handle, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||
app_handle.queries().connect().await.unwrap().get_key_value_int(NAMESPACE, NUM_LAUNCHES_KEY, 0)
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ use tokio::fs::{create_dir_all, File};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::watch::Receiver;
|
||||
use tokio::sync::{oneshot, Mutex};
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::models::{
|
||||
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader,
|
||||
HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||
};
|
||||
use yaak_models::queries::{
|
||||
get_base_environment, get_http_response, get_or_create_settings, get_workspace,
|
||||
update_response_if_id, upsert_cookie_jar, UpdateSource,
|
||||
};
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
use yaak_plugins::events::{
|
||||
CallHttpAuthenticationRequest, HttpHeader, RenderPurpose, WindowContext,
|
||||
};
|
||||
@@ -48,10 +46,18 @@ pub async fn send_http_request<R: Runtime>(
|
||||
) -> Result<HttpResponse> {
|
||||
let app_handle = window.app_handle().clone();
|
||||
let plugin_manager = app_handle.state::<PluginManager>();
|
||||
let workspace = get_workspace(&app_handle, &unrendered_request.workspace_id).await?;
|
||||
let base_environment =
|
||||
get_base_environment(&app_handle, &unrendered_request.workspace_id).await?;
|
||||
let settings = get_or_create_settings(&app_handle).await;
|
||||
let update_source = &UpdateSource::from_window(&window);
|
||||
let (settings, workspace) = {
|
||||
let db = window.queries().connect().await?;
|
||||
let settings = db.get_or_create_settings(update_source)?;
|
||||
let workspace = db.get_workspace(&unrendered_request.workspace_id)?;
|
||||
(settings, workspace)
|
||||
};
|
||||
let base_environment = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_base_environment(&unrendered_request.workspace_id)?;
|
||||
|
||||
let response_id = og_response.id.clone();
|
||||
let response = Arc::new(Mutex::new(og_response.clone()));
|
||||
@@ -534,8 +540,12 @@ pub async fn send_http_request<R: Runtime>(
|
||||
};
|
||||
|
||||
r.state = HttpResponseState::Connected;
|
||||
update_response_if_id(&app_handle, &r, &update_source)
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.update_http_response_if_id(&r, &update_source)
|
||||
.expect("Failed to update response after connected");
|
||||
}
|
||||
|
||||
@@ -563,8 +573,12 @@ pub async fn send_http_request<R: Runtime>(
|
||||
f.flush().await.expect("Failed to flush file");
|
||||
written_bytes += bytes.len();
|
||||
r.content_length = Some(written_bytes as i32);
|
||||
update_response_if_id(&app_handle, &r, &update_source)
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.update_http_response_if_id(&r, &update_source)
|
||||
.expect("Failed to update response");
|
||||
}
|
||||
Ok(None) => {
|
||||
@@ -591,8 +605,12 @@ pub async fn send_http_request<R: Runtime>(
|
||||
None => Some(written_bytes as i32),
|
||||
};
|
||||
r.state = HttpResponseState::Closed;
|
||||
update_response_if_id(&app_handle, &r, &UpdateSource::from_window(&window))
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.update_http_response_if_id(&r, &UpdateSource::from_window(&window))
|
||||
.expect("Failed to update response");
|
||||
};
|
||||
|
||||
@@ -617,12 +635,12 @@ pub async fn send_http_request<R: Runtime>(
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
cookie_jar.cookies = json_cookies;
|
||||
if let Err(e) = upsert_cookie_jar(
|
||||
&app_handle,
|
||||
&cookie_jar,
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
if let Err(e) = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_cookie_jar(&cookie_jar, &UpdateSource::from_window(&window))
|
||||
{
|
||||
error!("Failed to update cookie jar: {}", e);
|
||||
};
|
||||
@@ -649,10 +667,16 @@ pub async fn send_http_request<R: Runtime>(
|
||||
Ok(tokio::select! {
|
||||
Ok(r) = done_rx => r,
|
||||
_ = cancelled_rx.changed() => {
|
||||
match get_http_response(&app_handle, response_id.as_str()).await {
|
||||
match app_handle.queries().with_conn(|c| c.get_http_response(&response_id)).await {
|
||||
Ok(mut r) => {
|
||||
r.state = HttpResponseState::Closed;
|
||||
update_response_if_id(&app_handle, &r, &UpdateSource::from_window(window)).await.expect("Failed to update response")
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.update_http_response_if_id(&r, &UpdateSource::from_window(window))
|
||||
.expect("Failed to update response")
|
||||
},
|
||||
_ => {
|
||||
response_err(&app_handle, &*response.lock().await, "Ephemeral request was cancelled".to_string(), &update_source).await
|
||||
|
||||
1113
src-tauri/src/lib.rs
1113
src-tauri/src/lib.rs
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,8 @@ use reqwest::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tauri::{AppHandle, Emitter, Manager, Runtime, WebviewWindow};
|
||||
use yaak_models::queries::{get_key_value_raw, set_key_value_raw, UpdateSource};
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
|
||||
// Check for updates every hour
|
||||
const MAX_UPDATE_CHECK_SECONDS: u64 = 60 * 60;
|
||||
@@ -43,13 +44,22 @@ impl YaakNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn seen<R: Runtime>(&mut self, window: &WebviewWindow<R>, id: &str) -> Result<(), String> {
|
||||
pub async fn seen<R: Runtime>(
|
||||
&mut self,
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<(), String> {
|
||||
let app_handle = window.app_handle();
|
||||
let mut seen = get_kv(app_handle).await?;
|
||||
seen.push(id.to_string());
|
||||
debug!("Marked notification as seen {}", id);
|
||||
let seen_json = serde_json::to_string(&seen).map_err(|e| e.to_string())?;
|
||||
set_key_value_raw(app_handle, KV_NAMESPACE, KV_KEY, seen_json.as_str(), &UpdateSource::from_window(window)).await;
|
||||
window.queries().connect().await.map_err(|e| e.to_string())?.set_key_value_raw(
|
||||
KV_NAMESPACE,
|
||||
KV_KEY,
|
||||
seen_json.as_str(),
|
||||
&UpdateSource::from_window(window),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -70,7 +80,7 @@ impl YaakNotifier {
|
||||
.query(&[
|
||||
("version", info.version.to_string().as_str()),
|
||||
("launches", num_launches.to_string().as_str()),
|
||||
("platform", get_os())
|
||||
("platform", get_os()),
|
||||
]);
|
||||
let resp = req.send().await.map_err(|e| e.to_string())?;
|
||||
if resp.status() != 200 {
|
||||
@@ -108,7 +118,13 @@ impl YaakNotifier {
|
||||
}
|
||||
|
||||
async fn get_kv<R: Runtime>(app_handle: &AppHandle<R>) -> Result<Vec<String>, String> {
|
||||
match get_key_value_raw(app_handle, "notifications", "seen").await {
|
||||
match app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.get_key_value_raw("notifications", "seen")
|
||||
{
|
||||
None => Ok(Vec::new()),
|
||||
Some(v) => serde_json::from_str(&v.value).map_err(|e| e.to_string()),
|
||||
}
|
||||
|
||||
@@ -9,12 +9,9 @@ use chrono::Utc;
|
||||
use log::warn;
|
||||
use tauri::{AppHandle, Emitter, Manager, Runtime, State};
|
||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::models::{HttpResponse, Plugin};
|
||||
use yaak_models::queries::{
|
||||
create_default_http_response, delete_plugin_key_value, get_base_environment, get_http_request,
|
||||
get_plugin_key_value, list_http_responses_for_request, list_plugins, set_plugin_key_value,
|
||||
upsert_plugin, UpdateSource,
|
||||
};
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
use yaak_plugins::events::{
|
||||
Color, DeleteKeyValueResponse, EmptyPayload, FindHttpResponsesResponse,
|
||||
GetHttpRequestByIdResponse, GetKeyValueResponse, Icon, InternalEvent, InternalEventPayload,
|
||||
@@ -55,19 +52,28 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
call_frontend(window, event).await
|
||||
}
|
||||
InternalEventPayload::FindHttpResponsesRequest(req) => {
|
||||
let http_responses = list_http_responses_for_request(
|
||||
app_handle,
|
||||
req.request_id.as_str(),
|
||||
req.limit.map(|l| l as i64),
|
||||
)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let http_responses = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.list_http_responses_for_request(
|
||||
req.request_id.as_str(),
|
||||
req.limit.map(|l| l as u64),
|
||||
)
|
||||
.unwrap_or_default();
|
||||
Some(InternalEventPayload::FindHttpResponsesResponse(FindHttpResponsesResponse {
|
||||
http_responses,
|
||||
}))
|
||||
}
|
||||
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
||||
let http_request = get_http_request(app_handle, req.id.as_str()).await.unwrap();
|
||||
let http_request = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_http_request(req.id.as_str())
|
||||
.unwrap();
|
||||
Some(InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse {
|
||||
http_request,
|
||||
}))
|
||||
@@ -80,8 +86,12 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let base_environment = get_base_environment(app_handle, workspace.id.as_str())
|
||||
let base_environment = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_base_environment(&workspace.id)
|
||||
.expect("Failed to get base environment");
|
||||
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
|
||||
let http_request = render_http_request(
|
||||
@@ -104,8 +114,12 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
.await
|
||||
.expect("Failed to get workspace_id from window URL");
|
||||
let environment = environment_from_window(&window).await;
|
||||
let base_environment = get_base_environment(app_handle, workspace.id.as_str())
|
||||
let base_environment = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_base_environment(&workspace.id)
|
||||
.expect("Failed to get base environment");
|
||||
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
|
||||
let data = render_json_value(req.data, &base_environment, environment.as_ref(), &cb)
|
||||
@@ -135,7 +149,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
InternalEventPayload::ReloadResponse(_) => {
|
||||
let window = get_window_from_window_context(app_handle, &window_context)
|
||||
.expect("Failed to find window for plugin reload");
|
||||
let plugins = list_plugins(app_handle).await.unwrap();
|
||||
let plugins = app_handle.queries().connect().await.unwrap().list_plugins().unwrap();
|
||||
for plugin in plugins {
|
||||
if plugin.directory != plugin_handle.dir {
|
||||
continue;
|
||||
@@ -145,7 +159,13 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
updated_at: Utc::now().naive_utc(), // TODO: Add reloaded_at field to use instead
|
||||
..plugin
|
||||
};
|
||||
upsert_plugin(app_handle, new_plugin, &UpdateSource::Plugin).await.unwrap();
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_plugin(&new_plugin, &UpdateSource::Plugin)
|
||||
.unwrap();
|
||||
}
|
||||
let toast_event = plugin_handle.build_event_to_send(
|
||||
&WindowContext::from_window(&window),
|
||||
@@ -173,22 +193,29 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
http_request.workspace_id = workspace.id;
|
||||
}
|
||||
|
||||
let resp = if http_request.id.is_empty() {
|
||||
HttpResponse::new()
|
||||
let http_response = if http_request.id.is_empty() {
|
||||
HttpResponse::default()
|
||||
} else {
|
||||
create_default_http_response(
|
||||
app_handle,
|
||||
http_request.id.as_str(),
|
||||
&UpdateSource::Plugin,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
window
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_http_response(
|
||||
&HttpResponse {
|
||||
request_id: http_request.id.clone(),
|
||||
workspace_id: http_request.workspace_id.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::Plugin,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let result = send_http_request(
|
||||
&window,
|
||||
&http_request,
|
||||
&resp,
|
||||
&http_response,
|
||||
environment,
|
||||
cookie_jar,
|
||||
&mut tokio::sync::watch::channel(false).1, // No-op cancel channel
|
||||
@@ -265,17 +292,34 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
}
|
||||
InternalEventPayload::SetKeyValueRequest(req) => {
|
||||
let name = plugin_handle.name().await;
|
||||
set_plugin_key_value(app_handle, &name, &req.key, &req.value).await;
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.set_plugin_key_value(&name, &req.key, &req.value);
|
||||
Some(InternalEventPayload::SetKeyValueResponse(SetKeyValueResponse {}))
|
||||
}
|
||||
InternalEventPayload::GetKeyValueRequest(req) => {
|
||||
let name = plugin_handle.name().await;
|
||||
let value = get_plugin_key_value(app_handle, &name, &req.key).await.map(|v| v.value);
|
||||
let value = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.get_plugin_key_value(&name, &req.key)
|
||||
.map(|v| v.value);
|
||||
Some(InternalEventPayload::GetKeyValueResponse(GetKeyValueResponse { value }))
|
||||
}
|
||||
InternalEventPayload::DeleteKeyValueRequest(req) => {
|
||||
let name = plugin_handle.name().await;
|
||||
let deleted = delete_plugin_key_value(app_handle, &name, &req.key).await;
|
||||
let deleted = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.delete_plugin_key_value(&name, &req.key)
|
||||
.unwrap();
|
||||
Some(InternalEventPayload::DeleteKeyValueResponse(DeleteKeyValueResponse { deleted }))
|
||||
}
|
||||
_ => None,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::error::Result;
|
||||
use log::info;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tauri::{Manager, Runtime, WebviewWindow};
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons};
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
use tokio::task::block_in_place;
|
||||
use yaak_models::queries::get_or_create_settings;
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
use yaak_plugins::manager::PluginManager;
|
||||
|
||||
use crate::is_dev;
|
||||
@@ -59,30 +61,34 @@ impl YaakUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn check_now(
|
||||
pub async fn check_now<R: Runtime>(
|
||||
&mut self,
|
||||
app_handle: &AppHandle,
|
||||
window: &WebviewWindow<R>,
|
||||
mode: UpdateMode,
|
||||
update_trigger: UpdateTrigger,
|
||||
) -> Result<bool, tauri_plugin_updater::Error> {
|
||||
let settings = get_or_create_settings(app_handle).await;
|
||||
) -> Result<bool> {
|
||||
let settings = window
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_or_create_settings(&UpdateSource::from_window(window))?;
|
||||
let update_key = format!("{:x}", md5::compute(settings.id));
|
||||
self.last_update_check = SystemTime::now();
|
||||
|
||||
info!("Checking for updates mode={}", mode);
|
||||
|
||||
let h = app_handle.clone();
|
||||
let update_check_result = app_handle
|
||||
let w = window.clone();
|
||||
let update_check_result = w
|
||||
.updater_builder()
|
||||
.on_before_exit(move || {
|
||||
// Kill plugin manager before exit or NSIS installer will fail to replace sidecar
|
||||
// while it's running.
|
||||
// NOTE: This is only called on Windows
|
||||
let h = h.clone();
|
||||
let w = w.clone();
|
||||
block_in_place(|| {
|
||||
tauri::async_runtime::block_on(async move {
|
||||
info!("Shutting down plugin manager before update");
|
||||
let plugin_manager = h.state::<PluginManager>();
|
||||
let plugin_manager = w.state::<PluginManager>();
|
||||
plugin_manager.terminate().await;
|
||||
});
|
||||
});
|
||||
@@ -100,11 +106,11 @@ impl YaakUpdater {
|
||||
.check()
|
||||
.await;
|
||||
|
||||
match update_check_result {
|
||||
Ok(Some(update)) => {
|
||||
let h = app_handle.clone();
|
||||
app_handle
|
||||
.dialog()
|
||||
let result = match update_check_result? {
|
||||
None => false,
|
||||
Some(update) => {
|
||||
let w = window.clone();
|
||||
w.dialog()
|
||||
.message(format!(
|
||||
"{} is available. Would you like to download and install it now?",
|
||||
update.version
|
||||
@@ -121,7 +127,7 @@ impl YaakUpdater {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match update.download_and_install(|_, _| {}, || {}).await {
|
||||
Ok(_) => {
|
||||
if h.dialog()
|
||||
if w.dialog()
|
||||
.message("Would you like to restart the app?")
|
||||
.title("Update Installed")
|
||||
.buttons(MessageDialogButtons::OkCancelCustom(
|
||||
@@ -130,27 +136,27 @@ impl YaakUpdater {
|
||||
))
|
||||
.blocking_show()
|
||||
{
|
||||
h.restart();
|
||||
w.app_handle().restart();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
h.dialog()
|
||||
w.dialog()
|
||||
.message(format!("The update failed to install: {}", e));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Ok(true)
|
||||
true
|
||||
}
|
||||
Ok(None) => Ok(false),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
pub async fn maybe_check(
|
||||
pub async fn maybe_check<R: Runtime>(
|
||||
&mut self,
|
||||
app_handle: &AppHandle,
|
||||
window: &WebviewWindow<R>,
|
||||
mode: UpdateMode,
|
||||
) -> Result<bool, tauri_plugin_updater::Error> {
|
||||
) -> Result<bool> {
|
||||
let update_period_seconds = match mode {
|
||||
UpdateMode::Stable => MAX_UPDATE_CHECK_HOURS_STABLE,
|
||||
UpdateMode::Beta => MAX_UPDATE_CHECK_HOURS_BETA,
|
||||
@@ -167,6 +173,6 @@ impl YaakUpdater {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.check_now(app_handle, mode, UpdateTrigger::Background).await
|
||||
self.check_now(window, mode, UpdateTrigger::Background).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
git2 = { version = "0.20.0" , features = ["vendored-libgit2", "vendored-openssl"]}
|
||||
git2 = { version = "0.20.0", features = ["vendored-libgit2", "vendored-openssl"] }
|
||||
log = "0.4.22"
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.132"
|
||||
@@ -19,4 +19,4 @@ yaak-models = { workspace = true }
|
||||
yaak-sync = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { version = "2.0.3", features = ["build"] }
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"minimum": 1.0
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -111,7 +111,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"minimum": 1.0
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -111,7 +111,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -5,16 +5,16 @@ use crate::{
|
||||
};
|
||||
use log::{debug, info};
|
||||
use std::string::ToString;
|
||||
use tauri::{command, AppHandle, Manager, Runtime, WebviewWindow};
|
||||
use tauri::{command, Manager, Runtime, WebviewWindow};
|
||||
|
||||
#[command]
|
||||
pub async fn check<R: Runtime>(app_handle: AppHandle<R>) -> Result<LicenseCheckStatus> {
|
||||
pub async fn check<R: Runtime>(window: WebviewWindow<R>) -> Result<LicenseCheckStatus> {
|
||||
debug!("Checking license");
|
||||
check_license(
|
||||
&app_handle,
|
||||
&window,
|
||||
CheckActivationRequestPayload {
|
||||
app_platform: get_os().to_string(),
|
||||
app_version: app_handle.package_info().version.to_string(),
|
||||
app_version: window.package_info().version.to_string(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -12,6 +12,9 @@ pub enum Error {
|
||||
#[error("{message}")]
|
||||
ClientError { message: String, error: String },
|
||||
|
||||
#[error(transparent)]
|
||||
ModelError(#[from] yaak_models::error::Error),
|
||||
|
||||
#[error("Internal server error")]
|
||||
ServerError,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ use std::ops::Add;
|
||||
use std::time::Duration;
|
||||
use tauri::{is_dev, AppHandle, Emitter, Manager, Runtime, WebviewWindow};
|
||||
use ts_rs::TS;
|
||||
use yaak_models::queries::UpdateSource;
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
|
||||
const KV_NAMESPACE: &str = "license";
|
||||
const KV_ACTIVATION_ID_KEY: &str = "activation_id";
|
||||
@@ -80,14 +81,12 @@ pub async fn activate_license<R: Runtime>(
|
||||
}
|
||||
|
||||
let body: ActivateLicenseResponsePayload = response.json().await?;
|
||||
yaak_models::queries::set_key_value_string(
|
||||
window.app_handle(),
|
||||
window.app_handle().queries().connect().await?.set_key_value_string(
|
||||
KV_ACTIVATION_ID_KEY,
|
||||
KV_NAMESPACE,
|
||||
body.activation_id.as_str(),
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
|
||||
if let Err(e) = window.emit("license-activated", true) {
|
||||
warn!("Failed to emit check-license event: {}", e);
|
||||
@@ -119,13 +118,11 @@ pub async fn deactivate_license<R: Runtime>(
|
||||
return Err(ServerError);
|
||||
}
|
||||
|
||||
yaak_models::queries::delete_key_value(
|
||||
app_handle,
|
||||
app_handle.queries().connect().await?.delete_key_value(
|
||||
KV_ACTIVATION_ID_KEY,
|
||||
KV_NAMESPACE,
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await;
|
||||
)?;
|
||||
|
||||
if let Err(e) = app_handle.emit("license-deactivated", true) {
|
||||
warn!("Failed to emit deactivate-license event: {}", e);
|
||||
@@ -145,11 +142,15 @@ pub enum LicenseCheckStatus {
|
||||
}
|
||||
|
||||
pub async fn check_license<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
window: &WebviewWindow<R>,
|
||||
payload: CheckActivationRequestPayload,
|
||||
) -> Result<LicenseCheckStatus> {
|
||||
let activation_id = get_activation_id(app_handle).await;
|
||||
let settings = yaak_models::queries::get_or_create_settings(app_handle).await;
|
||||
let activation_id = get_activation_id(window.app_handle()).await;
|
||||
let settings = window
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_or_create_settings(&UpdateSource::from_window(window))?;
|
||||
let trial_end = settings.created_at.add(Duration::from_secs(TRIAL_SECONDS));
|
||||
|
||||
debug!("Trial ending at {trial_end:?}");
|
||||
@@ -200,6 +201,9 @@ fn build_url(path: &str) -> String {
|
||||
}
|
||||
|
||||
pub async fn get_activation_id<R: Runtime>(app_handle: &AppHandle<R>) -> String {
|
||||
yaak_models::queries::get_key_value_string(app_handle, KV_ACTIVATION_ID_KEY, KV_NAMESPACE, "")
|
||||
.await
|
||||
app_handle.queries().connect().await.unwrap().get_key_value_string(
|
||||
KV_ACTIVATION_ID_KEY,
|
||||
KV_NAMESPACE,
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[package]
|
||||
name = "yaak-models"
|
||||
links = "yaak-models"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
@@ -18,4 +19,8 @@ serde_json = "1.0.122"
|
||||
sqlx = { version = "0.8.0", default-features = false, features = ["migrate", "sqlite", "runtime-tokio-rustls"] }
|
||||
tauri = { workspace = true }
|
||||
thiserror = "2.0.11"
|
||||
tokio = "1.43.0"
|
||||
ts-rs = { workspace = true, features = ["chrono-impl", "serde-json-impl"] }
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AnyModel = CookieJar | Environment | Folder | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | Plugin | Settings | KeyValue | Workspace | WorkspaceMeta | WebsocketConnection | WebsocketEvent | WebsocketRequest;
|
||||
export type AnyModel = CookieJar | Environment | Folder | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | KeyValue | Plugin | Settings | SyncState | WebsocketConnection | WebsocketEvent | WebsocketRequest | Workspace | WorkspaceMeta;
|
||||
|
||||
export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], };
|
||||
|
||||
@@ -44,7 +44,9 @@ export type HttpUrlParameter = { enabled?: boolean, name: string, value: string,
|
||||
|
||||
export type KeyValue = { model: "key_value", createdAt: string, updatedAt: string, key: string, namespace: string, value: string, };
|
||||
|
||||
export type ModelPayload = { model: AnyModel, updateSource: UpdateSource, };
|
||||
export type ModelChangeEvent = { "type": "upsert" } | { "type": "delete" };
|
||||
|
||||
export type ModelPayload = { model: AnyModel, updateSource: UpdateSource, change: ModelChangeEvent, };
|
||||
|
||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, };
|
||||
|
||||
@@ -56,8 +58,6 @@ export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, theme: string, themeDark: string, themeLight: string, updateChannel: string, editorKeymap: EditorKeymap, };
|
||||
|
||||
export type SyncHistory = { model: "sync_history", id: string, workspaceId: string, createdAt: string, states: Array<SyncState>, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
export type UpdateSource = { "type": "sync" } | { "type": "window", label: string, } | { "type": "plugin" } | { "type": "background" } | { "type": "import" };
|
||||
|
||||
5
src-tauri/yaak-models/build.rs
Normal file
5
src-tauri/yaak-models/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
const COMMANDS: &[&str] = &["upsert", "delete"];
|
||||
|
||||
fn main() {
|
||||
tauri_plugin::Builder::new(COMMANDS).build();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-delete"
|
||||
description = "Enables the delete command without any pre-configured scope."
|
||||
commands.allow = ["delete"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-delete"
|
||||
description = "Denies the delete command without any pre-configured scope."
|
||||
commands.deny = ["delete"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-delete-model"
|
||||
description = "Enables the delete_model command without any pre-configured scope."
|
||||
commands.allow = ["delete_model"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-delete-model"
|
||||
description = "Denies the delete_model command without any pre-configured scope."
|
||||
commands.deny = ["delete_model"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-upsert"
|
||||
description = "Enables the upsert command without any pre-configured scope."
|
||||
commands.allow = ["upsert"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-upsert"
|
||||
description = "Denies the upsert command without any pre-configured scope."
|
||||
commands.deny = ["upsert"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-upsert-model"
|
||||
description = "Enables the upsert_model command without any pre-configured scope."
|
||||
commands.allow = ["upsert_model"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-upsert-model"
|
||||
description = "Denies the upsert_model command without any pre-configured scope."
|
||||
commands.deny = ["upsert_model"]
|
||||
120
src-tauri/yaak-models/permissions/autogenerated/reference.md
Normal file
120
src-tauri/yaak-models/permissions/autogenerated/reference.md
Normal file
@@ -0,0 +1,120 @@
|
||||
## Default Permission
|
||||
|
||||
Default permissions for the plugin
|
||||
|
||||
- `allow-upsert`
|
||||
- `allow-delete`
|
||||
|
||||
## Permission Table
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Identifier</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-delete`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the delete command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-delete`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the delete command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-delete-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the delete_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-delete-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the delete_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-upsert`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the upsert command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-upsert`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the upsert command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:allow-upsert-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the upsert_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-models:deny-upsert-model`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the upsert_model command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
6
src-tauri/yaak-models/permissions/default.toml
Normal file
6
src-tauri/yaak-models/permissions/default.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[default]
|
||||
description = "Default permissions for the plugin"
|
||||
permissions = [
|
||||
"allow-upsert",
|
||||
"allow-delete",
|
||||
]
|
||||
345
src-tauri/yaak-models/permissions/schemas/schema.json
Normal file
345
src-tauri/yaak-models/permissions/schemas/schema.json
Normal file
@@ -0,0 +1,345 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "PermissionFile",
|
||||
"description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default": {
|
||||
"description": "The default permission set for the plugin",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/DefaultPermission"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"set": {
|
||||
"description": "A list of permissions sets defined",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PermissionSet"
|
||||
}
|
||||
},
|
||||
"permission": {
|
||||
"description": "A list of inlined permissions",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Permission"
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"DefaultPermission": {
|
||||
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"permissions"
|
||||
],
|
||||
"properties": {
|
||||
"version": {
|
||||
"description": "The version of the permission.",
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
],
|
||||
"format": "uint64",
|
||||
"minimum": 1.0
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"description": "All permissions this set contains.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PermissionSet": {
|
||||
"description": "A set of direct permissions grouped together under a new name.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"description",
|
||||
"identifier",
|
||||
"permissions"
|
||||
],
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"description": "A unique identifier for the permission.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does.",
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"description": "All permissions this set contains.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/PermissionKind"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Permission": {
|
||||
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier"
|
||||
],
|
||||
"properties": {
|
||||
"version": {
|
||||
"description": "The version of the permission.",
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
],
|
||||
"format": "uint64",
|
||||
"minimum": 1.0
|
||||
},
|
||||
"identifier": {
|
||||
"description": "A unique identifier for the permission.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"commands": {
|
||||
"description": "Allowed or denied commands when using this permission.",
|
||||
"default": {
|
||||
"allow": [],
|
||||
"deny": []
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Commands"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scope": {
|
||||
"description": "Allowed or denied scoped when using this permission.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Scopes"
|
||||
}
|
||||
]
|
||||
},
|
||||
"platforms": {
|
||||
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Target"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Commands": {
|
||||
"description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": {
|
||||
"description": "Allowed command.",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"deny": {
|
||||
"description": "Denied command, which takes priority.",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Scopes": {
|
||||
"description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow": {
|
||||
"description": "Data that defines what is allowed by the scope.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
},
|
||||
"deny": {
|
||||
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Value": {
|
||||
"description": "All supported ACL values.",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Represents a null JSON value.",
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"description": "Represents a [`bool`].",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"description": "Represents a valid ACL [`Number`].",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Number"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Represents a [`String`].",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Represents a list of other [`Value`]s.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Represents a map of [`String`] keys to [`Value`]s.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Number": {
|
||||
"description": "A valid ACL number.",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Represents an [`i64`].",
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
{
|
||||
"description": "Represents a [`f64`].",
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Target": {
|
||||
"description": "Platform target.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "MacOS.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"macOS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Windows.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Linux.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Android.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "iOS.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"iOS"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"PermissionKind": {
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Enables the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-delete"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-delete"
|
||||
},
|
||||
{
|
||||
"description": "Enables the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the delete_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-delete-model"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-upsert"
|
||||
},
|
||||
{
|
||||
"description": "Enables the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Denies the upsert_model command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-upsert-model"
|
||||
},
|
||||
{
|
||||
"description": "Default permissions for the plugin",
|
||||
"type": "string",
|
||||
"const": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src-tauri/yaak-models/src/commands.rs
Normal file
24
src-tauri/yaak-models/src/commands.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::QueryManagerExt;
|
||||
use crate::models::AnyModel;
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use tauri::{Runtime, WebviewWindow};
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn upsert<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
model: AnyModel,
|
||||
) -> Result<String> {
|
||||
let queries = window.queries().connect().await?;
|
||||
let id = match model {
|
||||
AnyModel::HttpRequest(r) => queries.upsert(&r, &UpdateSource::from_window(&window))?.id,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn delete() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use serde::{Serialize, Serializer};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -11,11 +12,29 @@ pub enum Error {
|
||||
#[error("JSON error: {0}")]
|
||||
JsonError(#[from] serde_json::Error),
|
||||
|
||||
#[error("Model not found {0}")]
|
||||
#[error("Model not found: {0}")]
|
||||
ModelNotFound(String),
|
||||
|
||||
#[error("Model serialization error: {0}")]
|
||||
ModelSerializationError(String),
|
||||
|
||||
#[error("Model error: {0}")]
|
||||
GenericError(String),
|
||||
|
||||
#[error("Row not found")]
|
||||
RowNotFound,
|
||||
|
||||
#[error("unknown error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@@ -1,7 +1,98 @@
|
||||
use crate::commands::{delete, upsert};
|
||||
use crate::manager::QueryManager;
|
||||
use crate::queries_legacy::ModelChangeEvent;
|
||||
use log::info;
|
||||
use r2d2::Pool;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::SqliteConnectOptions;
|
||||
use sqlx::SqlitePool;
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tauri::async_runtime::Mutex;
|
||||
use tauri::path::BaseDirectory;
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{generate_handler, AppHandle, Emitter, Manager, Runtime};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
mod commands;
|
||||
|
||||
pub mod error;
|
||||
pub mod manager;
|
||||
pub mod models;
|
||||
pub mod queries;
|
||||
|
||||
pub mod plugin;
|
||||
pub mod queries_legacy;
|
||||
pub mod render;
|
||||
pub mod manager;
|
||||
|
||||
pub struct SqliteConnection(pub Mutex<Pool<SqliteConnectionManager>>);
|
||||
|
||||
impl SqliteConnection {
|
||||
pub(crate) fn new(pool: Pool<SqliteConnectionManager>) -> Self {
|
||||
Self(Mutex::new(pool))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("yaak_models")
|
||||
.invoke_handler(generate_handler![upsert, delete])
|
||||
.setup(|app_handle, _api| {
|
||||
let app_path = app_handle.path().app_data_dir().unwrap();
|
||||
create_dir_all(app_path.clone()).expect("Problem creating App directory!");
|
||||
|
||||
let db_file_path = app_path.join("db.sqlite");
|
||||
|
||||
{
|
||||
let db_file_path = db_file_path.clone();
|
||||
tauri::async_runtime::block_on(async move {
|
||||
must_migrate_db(app_handle.app_handle(), &db_file_path).await;
|
||||
});
|
||||
};
|
||||
|
||||
let manager = SqliteConnectionManager::file(db_file_path);
|
||||
let pool = Pool::builder()
|
||||
.max_size(100) // Up from 10 (just in case)
|
||||
.connection_timeout(Duration::from_secs(10)) // Down from 30
|
||||
.build(manager)
|
||||
.unwrap();
|
||||
|
||||
app_handle.manage(SqliteConnection::new(pool.clone()));
|
||||
|
||||
{
|
||||
let (tx, mut rx) = mpsc::channel(128);
|
||||
app_handle.manage(QueryManager::new(pool, tx));
|
||||
let app_handle = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
while let Some(p) = rx.recv().await {
|
||||
let name = match p.change {
|
||||
ModelChangeEvent::Upsert => "upserted_model",
|
||||
ModelChangeEvent::Delete => "deleted_model",
|
||||
};
|
||||
app_handle.emit(name, p).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
async fn must_migrate_db<R: Runtime>(app_handle: &AppHandle<R>, sqlite_file_path: &PathBuf) {
|
||||
info!("Connecting to database at {sqlite_file_path:?}");
|
||||
let sqlite_file_path = sqlite_file_path.to_str().unwrap().to_string();
|
||||
let opts = SqliteConnectOptions::from_str(&sqlite_file_path).unwrap().create_if_missing(true);
|
||||
let pool = SqlitePool::connect_with(opts).await.expect("Failed to connect to database");
|
||||
let p = app_handle
|
||||
.path()
|
||||
.resolve("migrations", BaseDirectory::Resource)
|
||||
.expect("failed to resolve resource");
|
||||
|
||||
info!("Running database migrations from: {}", p.to_string_lossy());
|
||||
let mut m = Migrator::new(p).await.expect("Failed to load migrations");
|
||||
m.set_ignore_missing(true); // So we can roll back versions and not crash
|
||||
m.run(&pool).await.expect("Failed to run migrations");
|
||||
|
||||
info!("Database migrations complete");
|
||||
}
|
||||
|
||||
@@ -1,40 +1,108 @@
|
||||
use crate::error::Result;
|
||||
use crate::models::{Workspace, WorkspaceIden};
|
||||
use crate::plugin::SqliteConnection;
|
||||
use crate::queries_legacy::ModelPayload;
|
||||
use r2d2::{Pool, PooledConnection};
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use rusqlite::Connection;
|
||||
use sea_query::{Asterisk, Order, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
use std::future::Future;
|
||||
use std::ops::Deref;
|
||||
use tauri::{AppHandle, Manager, Runtime};
|
||||
use rusqlite::{Connection, Statement, ToSql, Transaction, TransactionBehavior};
|
||||
use std::sync::Arc;
|
||||
use tauri::{Manager, Runtime};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
|
||||
pub struct QueryManager {
|
||||
pool: Pool<SqliteConnectionManager>,
|
||||
pub trait QueryManagerExt<'a, R> {
|
||||
fn queries(&'a self) -> &'a QueryManager;
|
||||
}
|
||||
|
||||
pub trait DBConnection {
|
||||
fn connect(
|
||||
&self,
|
||||
) -> impl Future<Output = Result<PooledConnection<SqliteConnectionManager>>> + Send;
|
||||
}
|
||||
|
||||
impl<R: Runtime> DBConnection for AppHandle<R> {
|
||||
async fn connect(&self) -> Result<PooledConnection<SqliteConnectionManager>> {
|
||||
let dbm = &*self.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get()?;
|
||||
Ok(db)
|
||||
impl<'a, R: Runtime, T: Manager<R>> QueryManagerExt<'a, R> for T {
|
||||
fn queries(&'a self) -> &'a QueryManager {
|
||||
let qm = self.state::<QueryManager>();
|
||||
qm.inner()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_workspaces<T: Deref<Target = Connection>>(c: &T) -> Result<Vec<Workspace>> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(WorkspaceIden::Table)
|
||||
.column(Asterisk)
|
||||
.order_by(WorkspaceIden::Name, Order::Asc)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = c.prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), |row| row.try_into())?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
#[derive(Clone)]
|
||||
pub struct QueryManager {
|
||||
pool: Arc<Mutex<Pool<SqliteConnectionManager>>>,
|
||||
events_tx: mpsc::Sender<ModelPayload>,
|
||||
}
|
||||
|
||||
impl QueryManager {
|
||||
pub(crate) fn new(
|
||||
pool: Pool<SqliteConnectionManager>,
|
||||
events_tx: mpsc::Sender<ModelPayload>,
|
||||
) -> Self {
|
||||
QueryManager {
|
||||
pool: Arc::new(Mutex::new(pool)),
|
||||
events_tx,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect(&self) -> Result<DbContext> {
|
||||
let conn = self.pool.lock().await.get()?;
|
||||
Ok(DbContext {
|
||||
tx: self.events_tx.clone(),
|
||||
conn: ConnectionOrTx::Connection(conn),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn with_conn<F, T>(&self, func: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&DbContext) -> Result<T>,
|
||||
{
|
||||
let conn = self.pool.lock().await.get()?;
|
||||
let db_context = DbContext {
|
||||
tx: self.events_tx.clone(),
|
||||
conn: ConnectionOrTx::Connection(conn),
|
||||
};
|
||||
func(&db_context)
|
||||
}
|
||||
|
||||
pub async fn with_tx<F, T>(&self, func: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&DbContext) -> Result<T>,
|
||||
{
|
||||
let mut conn = self.pool.lock().await.get()?;
|
||||
let tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
||||
|
||||
let db_context = DbContext {
|
||||
tx: self.events_tx.clone(),
|
||||
conn: ConnectionOrTx::Transaction(&tx),
|
||||
};
|
||||
|
||||
match func(&db_context) {
|
||||
Ok(val) => {
|
||||
tx.commit()?;
|
||||
Ok(val)
|
||||
}
|
||||
Err(e) => {
|
||||
tx.rollback()?;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ConnectionOrTx<'a> {
|
||||
Connection(PooledConnection<SqliteConnectionManager>),
|
||||
Transaction(&'a Transaction<'a>),
|
||||
}
|
||||
|
||||
impl<'a> ConnectionOrTx<'a> {
|
||||
pub(crate) fn resolve(&self) -> &Connection {
|
||||
match self {
|
||||
ConnectionOrTx::Connection(c) => c,
|
||||
ConnectionOrTx::Transaction(c) => c,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn prepare(&self, sql: &str) -> rusqlite::Result<Statement<'_>> {
|
||||
self.resolve().prepare(sql)
|
||||
}
|
||||
|
||||
pub(crate) fn execute(&self, sql: &str, params: &[&dyn ToSql]) -> rusqlite::Result<usize> {
|
||||
self.resolve().execute(sql, params)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DbContext<'a> {
|
||||
pub(crate) tx: mpsc::Sender<ModelPayload>,
|
||||
pub(crate) conn: ConnectionOrTx<'a>,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,81 +0,0 @@
|
||||
use log::info;
|
||||
use r2d2::Pool;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use serde::Deserialize;
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::SqliteConnectOptions;
|
||||
use sqlx::SqlitePool;
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tauri::async_runtime::Mutex;
|
||||
use tauri::path::BaseDirectory;
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{plugin, AppHandle, Manager, Runtime};
|
||||
|
||||
pub struct SqliteConnection(pub Mutex<Pool<SqliteConnectionManager>>);
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
pub struct PluginConfig {
|
||||
// Nothing yet (will be configurable in tauri.conf.json
|
||||
}
|
||||
|
||||
/// Tauri SQL plugin builder.
|
||||
#[derive(Default)]
|
||||
pub struct Builder {
|
||||
// Nothing Yet
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn build<R: Runtime>(&self) -> TauriPlugin<R, Option<PluginConfig>> {
|
||||
plugin::Builder::<R, Option<PluginConfig>>::new("yaak_models")
|
||||
.setup(|app, _api| {
|
||||
let app_path = app.path().app_data_dir().unwrap();
|
||||
create_dir_all(app_path.clone()).expect("Problem creating App directory!");
|
||||
|
||||
let db_file_path = app_path.join("db.sqlite");
|
||||
|
||||
{
|
||||
let db_file_path = db_file_path.clone();
|
||||
tauri::async_runtime::block_on(async move {
|
||||
must_migrate_db(app.app_handle(), &db_file_path).await;
|
||||
});
|
||||
};
|
||||
|
||||
let manager = SqliteConnectionManager::file(db_file_path);
|
||||
let pool = Pool::builder()
|
||||
.max_size(100) // Up from 10 (just in case)
|
||||
.connection_timeout(Duration::from_secs(10)) // Down from 30
|
||||
.build(manager)
|
||||
.unwrap();
|
||||
|
||||
app.manage(SqliteConnection(Mutex::new(pool)));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
async fn must_migrate_db<R: Runtime>(app_handle: &AppHandle<R>, sqlite_file_path: &PathBuf) {
|
||||
info!("Connecting to database at {sqlite_file_path:?}");
|
||||
let sqlite_file_path = sqlite_file_path.to_str().unwrap().to_string();
|
||||
let opts = SqliteConnectOptions::from_str(&sqlite_file_path).unwrap().create_if_missing(true);
|
||||
let pool = SqlitePool::connect_with(opts).await.expect("Failed to connect to database");
|
||||
let p = app_handle
|
||||
.path()
|
||||
.resolve("migrations", BaseDirectory::Resource)
|
||||
.expect("failed to resolve resource");
|
||||
|
||||
info!("Running database migrations from: {}", p.to_string_lossy());
|
||||
let mut m = Migrator::new(p).await.expect("Failed to load migrations");
|
||||
m.set_ignore_missing(true); // So we can roll back versions and not crash
|
||||
m.run(&pool).await.expect("Failed to run migrations");
|
||||
|
||||
info!("Database migrations complete");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
169
src-tauri/yaak-models/src/queries/base.rs
Normal file
169
src-tauri/yaak-models/src/queries/base.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use crate::error::Error::RowNotFound;
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{AnyModel, ModelType, UpsertModelInfo};
|
||||
use crate::queries_legacy::{generate_model_id, ModelChangeEvent, ModelPayload, UpdateSource};
|
||||
use rusqlite::OptionalExtension;
|
||||
use sea_query::{
|
||||
Asterisk, Expr, IntoColumnRef, IntoIden, IntoTableRef, OnConflict, Query, SimpleExpr,
|
||||
SqliteQueryBuilder,
|
||||
};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
pub(crate) const MAX_HISTORY_ITEMS: usize = 20;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub(crate) fn find_one<'s, M>(
|
||||
&self,
|
||||
col: impl IntoColumnRef,
|
||||
value: impl Into<SimpleExpr>,
|
||||
) -> Result<M>
|
||||
where
|
||||
M: Into<AnyModel> + Clone + UpsertModelInfo,
|
||||
{
|
||||
match self.find_optional::<M>(col, value) {
|
||||
Ok(Some(v)) => Ok(v),
|
||||
Ok(None) => Err(RowNotFound),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_optional<'s, M>(
|
||||
&self,
|
||||
col: impl IntoColumnRef,
|
||||
value: impl Into<SimpleExpr>,
|
||||
) -> Result<Option<M>>
|
||||
where
|
||||
M: Into<AnyModel> + Clone + UpsertModelInfo,
|
||||
{
|
||||
let (sql, params) = Query::select()
|
||||
.from(M::table_name())
|
||||
.column(Asterisk)
|
||||
.cond_where(Expr::col(col).eq(value))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
Ok(stmt.query_row(&*params.as_params(), M::from_row).optional()?)
|
||||
}
|
||||
|
||||
pub fn find_all<'s, M>(&self) -> Result<Vec<M>>
|
||||
where
|
||||
M: Into<AnyModel> + Clone + UpsertModelInfo,
|
||||
{
|
||||
let (sql, params) = Query::select()
|
||||
.from(M::table_name())
|
||||
.column(Asterisk)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.resolve().prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), M::from_row)?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub fn find_many<'s, M>(
|
||||
&self,
|
||||
col: impl IntoColumnRef,
|
||||
value: impl Into<SimpleExpr>,
|
||||
limit: Option<u64>,
|
||||
) -> Result<Vec<M>>
|
||||
where
|
||||
M: Into<AnyModel> + Clone + UpsertModelInfo,
|
||||
{
|
||||
// TODO: Figure out how to do this conditional builder better
|
||||
let (sql, params) = if let Some(limit) = limit {
|
||||
Query::select()
|
||||
.from(M::table_name())
|
||||
.column(Asterisk)
|
||||
.cond_where(Expr::col(col).eq(value))
|
||||
.limit(limit)
|
||||
.build_rusqlite(SqliteQueryBuilder)
|
||||
} else {
|
||||
Query::select()
|
||||
.from(M::table_name())
|
||||
.column(Asterisk)
|
||||
.cond_where(Expr::col(col).eq(value))
|
||||
.build_rusqlite(SqliteQueryBuilder)
|
||||
};
|
||||
|
||||
let mut stmt = self.conn.resolve().prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), M::from_row)?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub fn upsert<M>(&self, model: &M, source: &UpdateSource) -> Result<M>
|
||||
where
|
||||
M: Into<AnyModel> + From<AnyModel> + UpsertModelInfo + Clone,
|
||||
{
|
||||
self.upsert_one(
|
||||
M::table_name(),
|
||||
M::id_column(),
|
||||
model.get_id().as_str(),
|
||||
|| generate_model_id(ModelType::TypeEnvironment),
|
||||
model.clone().insert_values(source)?,
|
||||
M::update_columns(),
|
||||
source,
|
||||
)
|
||||
}
|
||||
|
||||
fn upsert_one<M>(
|
||||
&self,
|
||||
table: impl IntoTableRef,
|
||||
id_col: impl IntoIden + Eq + Clone,
|
||||
id_val: &str,
|
||||
gen_id: fn() -> String,
|
||||
other_values: Vec<(impl IntoIden + Eq, impl Into<SimpleExpr>)>,
|
||||
update_columns: Vec<impl IntoIden>,
|
||||
source: &UpdateSource,
|
||||
) -> Result<M>
|
||||
where
|
||||
M: Into<AnyModel> + From<AnyModel> + UpsertModelInfo + Clone,
|
||||
{
|
||||
let id_iden = id_col.into_iden();
|
||||
let mut column_vec = vec![id_iden.clone()];
|
||||
let mut value_vec = vec![if id_val == "" { gen_id().into() } else { id_val.into() }];
|
||||
|
||||
for (col, val) in other_values {
|
||||
value_vec.push(val.into());
|
||||
column_vec.push(col.into_iden());
|
||||
}
|
||||
|
||||
let on_conflict = OnConflict::column(id_iden).update_columns(update_columns).to_owned();
|
||||
let (sql, params) = Query::insert()
|
||||
.into_table(table)
|
||||
.columns(column_vec)
|
||||
.values_panic(value_vec)
|
||||
.on_conflict(on_conflict)
|
||||
.returning_all()
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
|
||||
let mut stmt = self.conn.resolve().prepare(sql.as_str())?;
|
||||
let m: M = stmt.query_row(&*params.as_params(), |row| M::from_row(row))?;
|
||||
|
||||
let payload = ModelPayload {
|
||||
model: m.clone().into(),
|
||||
update_source: source.clone(),
|
||||
change: ModelChangeEvent::Upsert,
|
||||
};
|
||||
self.tx.try_send(payload).unwrap();
|
||||
|
||||
Ok(m)
|
||||
}
|
||||
|
||||
pub(crate) fn delete<'s, M>(&self, m: &M, update_source: &UpdateSource) -> Result<M>
|
||||
where
|
||||
M: Into<AnyModel> + Clone + UpsertModelInfo,
|
||||
{
|
||||
let (sql, params) = Query::delete()
|
||||
.from_table(M::table_name())
|
||||
.cond_where(Expr::col(M::id_column().into_iden()).eq(m.get_id()))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
self.conn.execute(sql.as_str(), &*params.as_params())?;
|
||||
|
||||
let payload = ModelPayload {
|
||||
model: m.clone().into(),
|
||||
update_source: update_source.clone(),
|
||||
change: ModelChangeEvent::Delete,
|
||||
};
|
||||
|
||||
self.tx.try_send(payload).unwrap();
|
||||
Ok(m.clone())
|
||||
}
|
||||
}
|
||||
99
src-tauri/yaak-models/src/queries/batch.rs
Normal file
99
src-tauri/yaak-models/src/queries/batch.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{Environment, Folder, GrpcRequest, HttpRequest, WebsocketRequest, Workspace};
|
||||
use crate::queries_legacy::{BatchUpsertResult, UpdateSource};
|
||||
use log::info;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn batch_upsert(
|
||||
&self,
|
||||
workspaces: Vec<Workspace>,
|
||||
environments: Vec<Environment>,
|
||||
folders: Vec<Folder>,
|
||||
http_requests: Vec<HttpRequest>,
|
||||
grpc_requests: Vec<GrpcRequest>,
|
||||
websocket_requests: Vec<WebsocketRequest>,
|
||||
source: &UpdateSource,
|
||||
) -> Result<BatchUpsertResult> {
|
||||
let mut imported_resources = BatchUpsertResult::default();
|
||||
|
||||
if workspaces.len() > 0 {
|
||||
info!("Batch inserting {} workspaces", workspaces.len());
|
||||
for v in workspaces {
|
||||
let x = self.upsert_workspace(&v, source)?;
|
||||
imported_resources.workspaces.push(x.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if environments.len() > 0 {
|
||||
while imported_resources.environments.len() < environments.len() {
|
||||
for v in environments.clone() {
|
||||
if let Some(id) = v.environment_id.clone() {
|
||||
let has_parent_to_import =
|
||||
environments.iter().find(|m| m.id == id).is_some();
|
||||
let imported_parent =
|
||||
imported_resources.environments.iter().find(|m| m.id == id);
|
||||
// If there's also a parent to upsert, wait for that one
|
||||
if imported_parent.is_none() && has_parent_to_import {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(_) = imported_resources.environments.iter().find(|f| f.id == v.id) {
|
||||
continue;
|
||||
}
|
||||
let x = self.upsert_environment(&v, source)?;
|
||||
imported_resources.environments.push(x.clone());
|
||||
}
|
||||
}
|
||||
info!("Imported {} environments", imported_resources.environments.len());
|
||||
}
|
||||
|
||||
if folders.len() > 0 {
|
||||
while imported_resources.folders.len() < folders.len() {
|
||||
for v in folders.clone() {
|
||||
if let Some(id) = v.folder_id.clone() {
|
||||
let has_parent_to_import = folders.iter().find(|m| m.id == id).is_some();
|
||||
let imported_parent =
|
||||
imported_resources.folders.iter().find(|m| m.id == id);
|
||||
// If there's also a parent to upsert, wait for that one
|
||||
if imported_parent.is_none() && has_parent_to_import {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(_) = imported_resources.folders.iter().find(|f| f.id == v.id) {
|
||||
continue;
|
||||
}
|
||||
let x = self.upsert_folder(&v, source)?;
|
||||
imported_resources.folders.push(x.clone());
|
||||
}
|
||||
}
|
||||
info!("Imported {} folders", imported_resources.folders.len());
|
||||
}
|
||||
|
||||
if http_requests.len() > 0 {
|
||||
for v in http_requests {
|
||||
let x = self.upsert(&v, source)?;
|
||||
imported_resources.http_requests.push(x.clone());
|
||||
}
|
||||
info!("Imported {} http_requests", imported_resources.http_requests.len());
|
||||
}
|
||||
|
||||
if grpc_requests.len() > 0 {
|
||||
for v in grpc_requests {
|
||||
let x = self.upsert_grpc_request(&v, source)?;
|
||||
imported_resources.grpc_requests.push(x.clone());
|
||||
}
|
||||
info!("Imported {} grpc_requests", imported_resources.grpc_requests.len());
|
||||
}
|
||||
|
||||
if websocket_requests.len() > 0 {
|
||||
for v in websocket_requests {
|
||||
let x = self.upsert_websocket_request(&v, source)?;
|
||||
imported_resources.websocket_requests.push(x.clone());
|
||||
}
|
||||
info!("Imported {} websocket_requests", imported_resources.websocket_requests.len());
|
||||
}
|
||||
|
||||
Ok(imported_resources)
|
||||
}
|
||||
}
|
||||
35
src-tauri/yaak-models/src/queries/cookie_jars.rs
Normal file
35
src-tauri/yaak-models/src/queries/cookie_jars.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{CookieJar, CookieJarIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_cookie_jar(&self, id: &str) -> Result<CookieJar> {
|
||||
self.find_one(CookieJarIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_cookie_jars(&self, workspace_id: &str) -> Result<Vec<CookieJar>> {
|
||||
self.find_many(CookieJarIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_cookie_jar(
|
||||
&self,
|
||||
cookie_jar: &CookieJar,
|
||||
source: &UpdateSource,
|
||||
) -> Result<CookieJar> {
|
||||
self.delete(cookie_jar, source)
|
||||
}
|
||||
|
||||
pub fn delete_cookie_jar_by_id(&self, id: &str, source: &UpdateSource) -> Result<CookieJar> {
|
||||
let cookie_jar = self.get_cookie_jar(id)?;
|
||||
self.delete_cookie_jar(&cookie_jar, source)
|
||||
}
|
||||
|
||||
pub fn upsert_cookie_jar(
|
||||
&self,
|
||||
cookie_jar: &CookieJar,
|
||||
source: &UpdateSource,
|
||||
) -> Result<CookieJar> {
|
||||
self.upsert(cookie_jar, source)
|
||||
}
|
||||
}
|
||||
79
src-tauri/yaak-models/src/queries/environments.rs
Normal file
79
src-tauri/yaak-models/src/queries/environments.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{Environment, EnvironmentIden, UpsertModelInfo};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use log::info;
|
||||
use sea_query::ColumnRef::Asterisk;
|
||||
use sea_query::{Cond, Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_environment(&self, id: &str) -> Result<Environment> {
|
||||
self.find_one(EnvironmentIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn get_base_environment(&self, workspace_id: &str) -> Result<Environment> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(EnvironmentIden::Table)
|
||||
.column(Asterisk)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(EnvironmentIden::WorkspaceId).eq(workspace_id))
|
||||
.add(Expr::col(EnvironmentIden::EnvironmentId).is_null()),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
Ok(stmt.query_row(&*params.as_params(), Environment::from_row)?)
|
||||
}
|
||||
|
||||
pub fn ensure_base_environment(&self, workspace_id: &str) -> Result<()> {
|
||||
let environments = self.list_environments(workspace_id)?;
|
||||
let base_environment = environments
|
||||
.iter()
|
||||
.find(|e| e.environment_id == None && e.workspace_id == workspace_id);
|
||||
|
||||
if let None = base_environment {
|
||||
info!("Creating base environment for {workspace_id}");
|
||||
self.upsert_environment(
|
||||
&Environment {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
name: "Global Variables".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::Background,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_environments(&self, workspace_id: &str) -> Result<Vec<Environment>> {
|
||||
self.find_many(EnvironmentIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_environment(
|
||||
&self,
|
||||
environment: &Environment,
|
||||
source: &UpdateSource,
|
||||
) -> Result<Environment> {
|
||||
for environment in
|
||||
self.find_many::<Environment>(EnvironmentIden::EnvironmentId, &environment.id, None)?
|
||||
{
|
||||
self.delete_environment(&environment, source)?;
|
||||
}
|
||||
self.delete(environment, source)
|
||||
}
|
||||
|
||||
pub fn delete_environment_by_id(&self, id: &str, source: &UpdateSource) -> Result<Environment> {
|
||||
let environment = self.get_environment(id)?;
|
||||
self.delete_environment(&environment, source)
|
||||
}
|
||||
|
||||
pub fn upsert_environment(
|
||||
&self,
|
||||
environment: &Environment,
|
||||
source: &UpdateSource,
|
||||
) -> Result<Environment> {
|
||||
self.upsert(environment, source)
|
||||
}
|
||||
}
|
||||
106
src-tauri/yaak-models/src/queries/folders.rs
Normal file
106
src-tauri/yaak-models/src/queries/folders.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{
|
||||
Folder, FolderIden, GrpcRequest, GrpcRequestIden, HttpRequest, HttpRequestIden,
|
||||
WebsocketRequest, WebsocketRequestIden,
|
||||
};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_folder(&self, id: &str) -> Result<Folder> {
|
||||
self.find_one(FolderIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_folders(&self, workspace_id: &str) -> Result<Vec<Folder>> {
|
||||
self.find_many(FolderIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_folder(&self, folder: &Folder, source: &UpdateSource) -> Result<Folder> {
|
||||
for folder in self.find_many::<Folder>(FolderIden::FolderId, &folder.id, None)? {
|
||||
self.delete_folder(&folder, source)?;
|
||||
}
|
||||
for request in self.find_many::<HttpRequest>(HttpRequestIden::FolderId, &folder.id, None)? {
|
||||
self.delete_http_request(&request, source)?;
|
||||
}
|
||||
for request in self.find_many::<GrpcRequest>(GrpcRequestIden::FolderId, &folder.id, None)? {
|
||||
self.delete_grpc_request(&request, source)?;
|
||||
}
|
||||
for request in
|
||||
self.find_many::<WebsocketRequest>(WebsocketRequestIden::FolderId, &folder.id, None)?
|
||||
{
|
||||
self.delete_websocket_request(&request, source)?;
|
||||
}
|
||||
self.delete(folder, source)
|
||||
}
|
||||
|
||||
pub fn delete_folder_by_id(&self, id: &str, source: &UpdateSource) -> Result<Folder> {
|
||||
let folder = self.get_folder(id)?;
|
||||
self.delete_folder(&folder, source)
|
||||
}
|
||||
|
||||
pub fn upsert_folder(&self, folder: &Folder, source: &UpdateSource) -> Result<Folder> {
|
||||
self.upsert(folder, source)
|
||||
}
|
||||
|
||||
pub fn duplicate_folder(&self, src_folder: &Folder, source: &UpdateSource) -> Result<Folder> {
|
||||
let workspace_id = src_folder.workspace_id.as_str();
|
||||
|
||||
let http_requests = self
|
||||
.find_many::<HttpRequest>(HttpRequestIden::WorkspaceId, workspace_id, None)?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let grpc_requests = self
|
||||
.find_many::<GrpcRequest>(GrpcRequestIden::WorkspaceId, workspace_id, None)?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let folders = self
|
||||
.find_many::<Folder>(FolderIden::WorkspaceId, workspace_id, None)?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let new_folder = self.upsert_folder(
|
||||
&Folder {
|
||||
id: "".into(),
|
||||
sort_priority: src_folder.sort_priority + 0.001,
|
||||
..src_folder.clone()
|
||||
},
|
||||
source,
|
||||
)?;
|
||||
|
||||
for m in http_requests {
|
||||
self.upsert_http_request(
|
||||
&HttpRequest {
|
||||
id: "".into(),
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
sort_priority: m.sort_priority + 0.001,
|
||||
..m
|
||||
},
|
||||
source,
|
||||
)?;
|
||||
}
|
||||
for m in grpc_requests {
|
||||
self.upsert_grpc_request(
|
||||
&GrpcRequest {
|
||||
id: "".into(),
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
sort_priority: m.sort_priority + 0.001,
|
||||
..m
|
||||
},
|
||||
source,
|
||||
)?;
|
||||
}
|
||||
for m in folders {
|
||||
// Recurse down
|
||||
self.duplicate_folder(
|
||||
&Folder {
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
..m
|
||||
},
|
||||
source,
|
||||
)?;
|
||||
}
|
||||
Ok(new_folder)
|
||||
}
|
||||
}
|
||||
98
src-tauri/yaak-models/src/queries/grpc_connections.rs
Normal file
98
src-tauri/yaak-models/src/queries/grpc_connections.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{GrpcConnection, GrpcConnectionIden, GrpcConnectionState};
|
||||
use crate::queries::base::MAX_HISTORY_ITEMS;
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use log::debug;
|
||||
use sea_query::{Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_grpc_connection(&self, id: &str) -> Result<GrpcConnection> {
|
||||
self.find_one(GrpcConnectionIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn delete_all_grpc_connections_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let responses = self.list_grpc_connections_for_request(request_id, None)?;
|
||||
for m in responses {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_all_grpc_connections_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
for m in self.list_grpc_connections_for_workspace(workspace_id, None)? {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_grpc_connection(
|
||||
&self,
|
||||
m: &GrpcConnection,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcConnection> {
|
||||
self.delete(m, source)
|
||||
}
|
||||
|
||||
pub fn delete_grpc_connection_by_id(
|
||||
&self,
|
||||
id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcConnection> {
|
||||
let grpc_connection = self.get_grpc_connection(id)?;
|
||||
self.delete_grpc_connection(&grpc_connection, source)
|
||||
}
|
||||
|
||||
pub fn list_grpc_connections_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
limit: Option<u64>,
|
||||
) -> Result<Vec<GrpcConnection>> {
|
||||
self.find_many(GrpcConnectionIden::RequestId, request_id, limit)
|
||||
}
|
||||
|
||||
pub fn list_grpc_connections_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
limit: Option<u64>,
|
||||
) -> Result<Vec<GrpcConnection>> {
|
||||
self.find_many(GrpcConnectionIden::WorkspaceId, workspace_id, limit)
|
||||
}
|
||||
|
||||
pub fn cancel_pending_grpc_connections(&self) -> Result<()> {
|
||||
let closed = serde_json::to_value(&GrpcConnectionState::Closed)?;
|
||||
let (sql, params) = Query::update()
|
||||
.table(GrpcConnectionIden::Table)
|
||||
.values([(GrpcConnectionIden::State, closed.as_str().into())])
|
||||
.cond_where(Expr::col(GrpcConnectionIden::State).ne(closed.as_str()))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
stmt.execute(&*params.as_params())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn upsert_grpc_connection(
|
||||
&self,
|
||||
grpc_connection: &GrpcConnection,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcConnection> {
|
||||
let connections =
|
||||
self.list_grpc_connections_for_request(grpc_connection.request_id.as_str(), None)?;
|
||||
|
||||
for m in connections.iter().skip(MAX_HISTORY_ITEMS - 1) {
|
||||
debug!("Deleting old gRPC connection {}", grpc_connection.id);
|
||||
self.delete_grpc_connection(&m, source)?;
|
||||
}
|
||||
|
||||
self.upsert(grpc_connection, source)
|
||||
}
|
||||
}
|
||||
22
src-tauri/yaak-models/src/queries/grpc_events.rs
Normal file
22
src-tauri/yaak-models/src/queries/grpc_events.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{GrpcEvent, GrpcEventIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_grpc_events(&self, id: &str) -> Result<GrpcEvent> {
|
||||
self.find_one(GrpcEventIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_grpc_events(&self, connection_id: &str) -> Result<Vec<GrpcEvent>> {
|
||||
self.find_many(GrpcEventIden::ConnectionId, connection_id, None)
|
||||
}
|
||||
|
||||
pub fn upsert_grpc_event(
|
||||
&self,
|
||||
grpc_event: &GrpcEvent,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcEvent> {
|
||||
self.upsert(grpc_event, source)
|
||||
}
|
||||
}
|
||||
51
src-tauri/yaak-models/src/queries/grpc_requests.rs
Normal file
51
src-tauri/yaak-models/src/queries/grpc_requests.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{GrpcRequest, GrpcRequestIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_grpc_request(&self, id: &str) -> Result<Option<GrpcRequest>> {
|
||||
self.find_optional(GrpcRequestIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_grpc_requests(&self, workspace_id: &str) -> Result<Vec<GrpcRequest>> {
|
||||
self.find_many(GrpcRequestIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_grpc_request(
|
||||
&self,
|
||||
m: &GrpcRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcRequest> {
|
||||
self.delete_all_grpc_connections_for_request(m.id.as_str(), source)?;
|
||||
self.delete(m, source)
|
||||
}
|
||||
|
||||
pub fn delete_grpc_request_by_id(
|
||||
&self,
|
||||
id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcRequest> {
|
||||
let request = self.get_grpc_request(id)?.unwrap();
|
||||
self.delete_grpc_request(&request, source)
|
||||
}
|
||||
|
||||
pub fn duplicate_grpc_request(
|
||||
&self,
|
||||
grpc_request: &GrpcRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcRequest> {
|
||||
let mut request = grpc_request.clone();
|
||||
request.id = "".to_string();
|
||||
request.sort_priority = request.sort_priority + 0.001;
|
||||
self.upsert(&request, source)
|
||||
}
|
||||
|
||||
pub fn upsert_grpc_request(
|
||||
&self,
|
||||
grpc_request: &GrpcRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GrpcRequest> {
|
||||
self.upsert(grpc_request, source)
|
||||
}
|
||||
}
|
||||
51
src-tauri/yaak-models/src/queries/http_requests.rs
Normal file
51
src-tauri/yaak-models/src/queries/http_requests.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{HttpRequest, HttpRequestIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_http_request(&self, id: &str) -> Result<Option<HttpRequest>> {
|
||||
self.find_optional(HttpRequestIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_http_requests(&self, workspace_id: &str) -> Result<Vec<HttpRequest>> {
|
||||
self.find_many(HttpRequestIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_http_request(
|
||||
&self,
|
||||
m: &HttpRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpRequest> {
|
||||
self.delete_all_http_responses_for_request(m.id.as_str(), source)?;
|
||||
self.delete(m, source)
|
||||
}
|
||||
|
||||
pub fn delete_http_request_by_id(
|
||||
&self,
|
||||
id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpRequest> {
|
||||
let http_request = self.get_http_request(id)?.unwrap();
|
||||
self.delete_http_request(&http_request, source)
|
||||
}
|
||||
|
||||
pub fn duplicate_http_request(
|
||||
&self,
|
||||
http_request: &HttpRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpRequest> {
|
||||
let mut http_request = http_request.clone();
|
||||
http_request.id = "".to_string();
|
||||
http_request.sort_priority = http_request.sort_priority + 0.001;
|
||||
self.upsert(&http_request, source)
|
||||
}
|
||||
|
||||
pub fn upsert_http_request(
|
||||
&self,
|
||||
http_request: &HttpRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpRequest> {
|
||||
self.upsert(http_request, source)
|
||||
}
|
||||
}
|
||||
110
src-tauri/yaak-models/src/queries/http_responses.rs
Normal file
110
src-tauri/yaak-models/src/queries/http_responses.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{HttpResponse, HttpResponseIden, HttpResponseState};
|
||||
use crate::queries::base::MAX_HISTORY_ITEMS;
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use log::{debug, error};
|
||||
use sea_query::{Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
use std::fs;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_http_response(&self, id: &str) -> Result<HttpResponse> {
|
||||
self.find_one(HttpResponseIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_http_responses_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
limit: Option<u64>,
|
||||
) -> Result<Vec<HttpResponse>> {
|
||||
self.find_many(HttpResponseIden::RequestId, request_id, limit)
|
||||
}
|
||||
|
||||
pub fn list_http_responses_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
limit: Option<u64>,
|
||||
) -> Result<Vec<HttpResponse>> {
|
||||
self.find_many(HttpResponseIden::WorkspaceId, workspace_id, limit)
|
||||
}
|
||||
|
||||
pub fn delete_all_http_responses_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let responses = self.list_http_responses_for_request(request_id, None)?;
|
||||
for m in responses {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_all_http_responses_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let responses =
|
||||
self.find_many::<HttpResponse>(HttpResponseIden::WorkspaceId, workspace_id, None)?;
|
||||
for m in responses {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_http_response(
|
||||
&self,
|
||||
http_response: &HttpResponse,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpResponse> {
|
||||
// Delete the body file if it exists
|
||||
if let Some(p) = http_response.body_path.clone() {
|
||||
if let Err(e) = fs::remove_file(p) {
|
||||
error!("Failed to delete body file: {}", e);
|
||||
};
|
||||
}
|
||||
|
||||
Ok(self.delete(http_response, source)?)
|
||||
}
|
||||
|
||||
pub fn upsert_http_response(
|
||||
&self,
|
||||
http_response: &HttpResponse,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpResponse> {
|
||||
let responses = self.list_http_responses_for_request(&http_response.request_id, None)?;
|
||||
|
||||
for m in responses.iter().skip(MAX_HISTORY_ITEMS - 1) {
|
||||
debug!("Deleting old HTTP response {}", http_response.id);
|
||||
self.delete_http_response(&m, source)?;
|
||||
}
|
||||
|
||||
self.upsert(http_response, source)
|
||||
}
|
||||
|
||||
pub fn cancel_pending_http_responses(&self) -> Result<()> {
|
||||
let closed = serde_json::to_value(&HttpResponseState::Closed)?;
|
||||
let (sql, params) = Query::update()
|
||||
.table(HttpResponseIden::Table)
|
||||
.values([(HttpResponseIden::State, closed.as_str().into())])
|
||||
.cond_where(Expr::col(HttpResponseIden::State).ne(closed.as_str()))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
stmt.execute(&*params.as_params())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_http_response_if_id(
|
||||
&self,
|
||||
response: &HttpResponse,
|
||||
source: &UpdateSource,
|
||||
) -> Result<HttpResponse> {
|
||||
if response.id.is_empty() {
|
||||
Ok(response.clone())
|
||||
} else {
|
||||
self.upsert(response, source)
|
||||
}
|
||||
}
|
||||
}
|
||||
164
src-tauri/yaak-models/src/queries/key_values.rs
Normal file
164
src-tauri/yaak-models/src/queries/key_values.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{KeyValue, KeyValueIden};
|
||||
use crate::queries_legacy::{ModelChangeEvent, ModelPayload, UpdateSource};
|
||||
use log::error;
|
||||
use sea_query::Keyword::CurrentTimestamp;
|
||||
use sea_query::{Asterisk, Cond, Expr, OnConflict, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn list_key_values_raw(&self) -> Result<Vec<KeyValue>> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(KeyValueIden::Table)
|
||||
.column(Asterisk)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), |row| row.try_into())?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub fn get_key_value_string(&self, namespace: &str, key: &str, default: &str) -> String {
|
||||
match self.get_key_value_raw(namespace, key) {
|
||||
None => default.to_string(),
|
||||
Some(v) => {
|
||||
let result = serde_json::from_str(&v.value);
|
||||
match result {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("Failed to parse string key value: {}", e);
|
||||
default.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_key_value_int(&self, namespace: &str, key: &str, default: i32) -> i32 {
|
||||
match self.get_key_value_raw(namespace, key) {
|
||||
None => default.clone(),
|
||||
Some(v) => {
|
||||
let result = serde_json::from_str(&v.value);
|
||||
match result {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("Failed to parse int key value: {}", e);
|
||||
default.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_key_value_raw(&self, namespace: &str, key: &str) -> Option<KeyValue> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(KeyValueIden::Table)
|
||||
.column(Asterisk)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(KeyValueIden::Namespace).eq(namespace))
|
||||
.add(Expr::col(KeyValueIden::Key).eq(key)),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
self.conn.resolve().query_row(sql.as_str(), &*params.as_params(), |row| row.try_into()).ok()
|
||||
}
|
||||
|
||||
pub fn set_key_value_string(
|
||||
&self,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: &str,
|
||||
source: &UpdateSource,
|
||||
) -> (KeyValue, bool) {
|
||||
let encoded = serde_json::to_string(&value).unwrap();
|
||||
self.set_key_value_raw(namespace, key, &encoded, source)
|
||||
}
|
||||
|
||||
pub fn set_key_value_int(
|
||||
&self,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: i32,
|
||||
source: &UpdateSource,
|
||||
) -> (KeyValue, bool) {
|
||||
let encoded = serde_json::to_string(&value).unwrap();
|
||||
self.set_key_value_raw(namespace, key, &encoded, source)
|
||||
}
|
||||
|
||||
pub fn set_key_value_raw(
|
||||
&self,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: &str,
|
||||
source: &UpdateSource,
|
||||
) -> (KeyValue, bool) {
|
||||
let existing = self.get_key_value_raw(namespace, key);
|
||||
|
||||
let (sql, params) = Query::insert()
|
||||
.into_table(KeyValueIden::Table)
|
||||
.columns([
|
||||
KeyValueIden::CreatedAt,
|
||||
KeyValueIden::UpdatedAt,
|
||||
KeyValueIden::Namespace,
|
||||
KeyValueIden::Key,
|
||||
KeyValueIden::Value,
|
||||
])
|
||||
.values_panic([
|
||||
CurrentTimestamp.into(),
|
||||
CurrentTimestamp.into(),
|
||||
namespace.into(),
|
||||
key.into(),
|
||||
value.into(),
|
||||
])
|
||||
.on_conflict(
|
||||
OnConflict::new()
|
||||
.update_columns([KeyValueIden::UpdatedAt, KeyValueIden::Value])
|
||||
.to_owned(),
|
||||
)
|
||||
.returning_all()
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
|
||||
let mut stmt = self.conn.prepare(sql.as_str()).expect("Failed to prepare KeyValue upsert");
|
||||
let m: KeyValue = stmt
|
||||
.query_row(&*params.as_params(), |row| row.try_into())
|
||||
.expect("Failed to upsert KeyValue");
|
||||
|
||||
let payload = ModelPayload {
|
||||
model: m.clone().into(),
|
||||
update_source: source.clone(),
|
||||
change: ModelChangeEvent::Upsert,
|
||||
};
|
||||
self.tx.try_send(payload).unwrap();
|
||||
|
||||
(m, existing.is_none())
|
||||
}
|
||||
|
||||
pub fn delete_key_value(
|
||||
&self,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let kv = match self.get_key_value_raw(namespace, key) {
|
||||
None => return Ok(()),
|
||||
Some(m) => m,
|
||||
};
|
||||
|
||||
let (sql, params) = Query::delete()
|
||||
.from_table(KeyValueIden::Table)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(KeyValueIden::Namespace).eq(namespace))
|
||||
.add(Expr::col(KeyValueIden::Key).eq(key)),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
self.conn.execute(sql.as_str(), &*params.as_params())?;
|
||||
let payload = ModelPayload {
|
||||
model: kv.clone().into(),
|
||||
update_source: source.clone(),
|
||||
change: ModelChangeEvent::Delete,
|
||||
};
|
||||
self.tx.try_send(payload).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
20
src-tauri/yaak-models/src/queries/mod.rs
Normal file
20
src-tauri/yaak-models/src/queries/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
mod base;
|
||||
mod batch;
|
||||
mod cookie_jars;
|
||||
mod environments;
|
||||
mod folders;
|
||||
mod grpc_connections;
|
||||
mod grpc_events;
|
||||
mod grpc_requests;
|
||||
mod http_requests;
|
||||
mod http_responses;
|
||||
mod key_values;
|
||||
mod plugin_key_values;
|
||||
mod plugins;
|
||||
mod settings;
|
||||
mod sync_states;
|
||||
mod websocket_connections;
|
||||
mod websocket_events;
|
||||
mod websocket_requests;
|
||||
mod workspace_metas;
|
||||
mod workspaces;
|
||||
79
src-tauri/yaak-models/src/queries/plugin_key_values.rs
Normal file
79
src-tauri/yaak-models/src/queries/plugin_key_values.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{PluginKeyValue, PluginKeyValueIden};
|
||||
use sea_query::Keyword::CurrentTimestamp;
|
||||
use sea_query::{Asterisk, Cond, Expr, OnConflict, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_plugin_key_value(&self, plugin_name: &str, key: &str) -> Option<PluginKeyValue> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(PluginKeyValueIden::Table)
|
||||
.column(Asterisk)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(PluginKeyValueIden::PluginName).eq(plugin_name))
|
||||
.add(Expr::col(PluginKeyValueIden::Key).eq(key)),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
self.conn.resolve().query_row(sql.as_str(), &*params.as_params(), |row| row.try_into()).ok()
|
||||
}
|
||||
|
||||
pub fn set_plugin_key_value(
|
||||
&self,
|
||||
plugin_name: &str,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) -> (PluginKeyValue, bool) {
|
||||
let existing = self.get_plugin_key_value(plugin_name, key);
|
||||
|
||||
let (sql, params) = Query::insert()
|
||||
.into_table(PluginKeyValueIden::Table)
|
||||
.columns([
|
||||
PluginKeyValueIden::CreatedAt,
|
||||
PluginKeyValueIden::UpdatedAt,
|
||||
PluginKeyValueIden::PluginName,
|
||||
PluginKeyValueIden::Key,
|
||||
PluginKeyValueIden::Value,
|
||||
])
|
||||
.values_panic([
|
||||
CurrentTimestamp.into(),
|
||||
CurrentTimestamp.into(),
|
||||
plugin_name.into(),
|
||||
key.into(),
|
||||
value.into(),
|
||||
])
|
||||
.on_conflict(
|
||||
OnConflict::new()
|
||||
.update_columns([PluginKeyValueIden::UpdatedAt, PluginKeyValueIden::Value])
|
||||
.to_owned(),
|
||||
)
|
||||
.returning_all()
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
|
||||
let mut stmt =
|
||||
self.conn.prepare(sql.as_str()).expect("Failed to prepare PluginKeyValue upsert");
|
||||
let m: PluginKeyValue = stmt
|
||||
.query_row(&*params.as_params(), |row| row.try_into())
|
||||
.expect("Failed to upsert KeyValue");
|
||||
|
||||
(m, existing.is_none())
|
||||
}
|
||||
|
||||
pub fn delete_plugin_key_value(&self, namespace: &str, key: &str) -> Result<bool> {
|
||||
if let None = self.get_plugin_key_value(namespace, key) {
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
let (sql, params) = Query::delete()
|
||||
.from_table(PluginKeyValueIden::Table)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(PluginKeyValueIden::PluginName).eq(namespace))
|
||||
.add(Expr::col(PluginKeyValueIden::Key).eq(key)),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
self.conn.execute(sql.as_str(), &*params.as_params())?;
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
27
src-tauri/yaak-models/src/queries/plugins.rs
Normal file
27
src-tauri/yaak-models/src/queries/plugins.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{Plugin, PluginIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_plugin(&self, id: &str) -> Result<Plugin> {
|
||||
self.find_one(PluginIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_plugins(&self) -> Result<Vec<Plugin>> {
|
||||
self.find_all()
|
||||
}
|
||||
|
||||
pub fn delete_plugin(&self, plugin: &Plugin, source: &UpdateSource) -> Result<Plugin> {
|
||||
self.delete(plugin, source)
|
||||
}
|
||||
|
||||
pub fn delete_plugin_by_id(&self, id: &str, source: &UpdateSource) -> Result<Plugin> {
|
||||
let plugin = self.get_plugin(id)?;
|
||||
self.delete_plugin(&plugin, source)
|
||||
}
|
||||
|
||||
pub fn upsert_plugin(&self, plugin: &Plugin, source: &UpdateSource) -> Result<Plugin> {
|
||||
self.upsert(plugin, source)
|
||||
}
|
||||
}
|
||||
25
src-tauri/yaak-models/src/queries/settings.rs
Normal file
25
src-tauri/yaak-models/src/queries/settings.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{Settings, SettingsIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_or_create_settings(&self, source: &UpdateSource) -> Result<Settings> {
|
||||
let id = "default";
|
||||
if let Some(s) = self.find_optional::<Settings>(SettingsIden::Id, id)? {
|
||||
return Ok(s);
|
||||
};
|
||||
|
||||
self.upsert(
|
||||
&Settings {
|
||||
id: id.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
source,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn upsert_settings(&self, settings: &Settings, source: &UpdateSource) -> Result<Settings> {
|
||||
self.upsert(settings, source)
|
||||
}
|
||||
}
|
||||
45
src-tauri/yaak-models/src/queries/sync_states.rs
Normal file
45
src-tauri/yaak-models/src/queries/sync_states.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{SyncState, SyncStateIden, UpsertModelInfo};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use sea_query::{Asterisk, Cond, Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
use std::path::Path;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_sync_state(&self, id: &str) -> Result<SyncState> {
|
||||
self.find_one(SyncStateIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn upsert_sync_state(&self, sync_state: &SyncState) -> Result<SyncState> {
|
||||
self.upsert(sync_state, &UpdateSource::Sync)
|
||||
}
|
||||
|
||||
pub fn list_sync_states_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
sync_dir: &Path,
|
||||
) -> Result<Vec<SyncState>> {
|
||||
let (sql, params) = Query::select()
|
||||
.from(SyncStateIden::Table)
|
||||
.column(Asterisk)
|
||||
.cond_where(
|
||||
Cond::all()
|
||||
.add(Expr::col(SyncStateIden::WorkspaceId).eq(workspace_id))
|
||||
.add(Expr::col(SyncStateIden::SyncDir).eq(sync_dir.to_string_lossy())),
|
||||
)
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
let items = stmt.query_map(&*params.as_params(), SyncState::from_row)?;
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub fn delete_sync_state(&self, sync_state: &SyncState) -> Result<SyncState> {
|
||||
self.delete(sync_state, &UpdateSource::Sync)
|
||||
}
|
||||
|
||||
pub fn delete_sync_state_by_id(&self, id: &str) -> Result<SyncState> {
|
||||
let sync_state = self.get_sync_state(id)?;
|
||||
self.delete_sync_state(&sync_state)
|
||||
}
|
||||
}
|
||||
97
src-tauri/yaak-models/src/queries/websocket_connections.rs
Normal file
97
src-tauri/yaak-models/src/queries/websocket_connections.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{WebsocketConnection, WebsocketConnectionIden, WebsocketConnectionState};
|
||||
use crate::queries::base::MAX_HISTORY_ITEMS;
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
use log::debug;
|
||||
use sea_query::{Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_websocket_connection(&self, id: &str) -> Result<WebsocketConnection> {
|
||||
self.find_one(WebsocketConnectionIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn delete_all_websocket_connections_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let responses = self.list_websocket_connections_for_request(request_id)?;
|
||||
for m in responses {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_all_websocket_connections_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<()> {
|
||||
let responses = self.list_websocket_connections_for_workspace(workspace_id)?;
|
||||
for m in responses {
|
||||
self.delete(&m, source)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_websocket_connections_for_workspace(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<WebsocketConnection>> {
|
||||
self.find_many(WebsocketConnectionIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn list_websocket_connections_for_request(
|
||||
&self,
|
||||
request_id: &str,
|
||||
) -> Result<Vec<WebsocketConnection>> {
|
||||
self.find_many(WebsocketConnectionIden::RequestId, request_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_websocket_connection(
|
||||
&self,
|
||||
websocket_connection: &WebsocketConnection,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketConnection> {
|
||||
self.delete(websocket_connection, source)
|
||||
}
|
||||
|
||||
pub fn delete_websocket_connection_by_id(
|
||||
&self,
|
||||
id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let websocket_connection = self.get_websocket_connection(id)?;
|
||||
self.delete_websocket_connection(&websocket_connection, source)
|
||||
}
|
||||
|
||||
pub fn upsert_websocket_connection(
|
||||
&self,
|
||||
websocket_connection: &WebsocketConnection,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let connections =
|
||||
self.list_websocket_connections_for_request(&websocket_connection.request_id)?;
|
||||
|
||||
for m in connections.iter().skip(MAX_HISTORY_ITEMS - 1) {
|
||||
debug!("Deleting old websocket connection {}", websocket_connection.id);
|
||||
self.delete_websocket_connection(&m, source)?;
|
||||
}
|
||||
|
||||
self.upsert(websocket_connection, source)
|
||||
}
|
||||
|
||||
pub fn cancel_pending_websocket_connections(&self) -> Result<()> {
|
||||
let closed = serde_json::to_value(&WebsocketConnectionState::Closed)?;
|
||||
let (sql, params) = Query::update()
|
||||
.table(WebsocketConnectionIden::Table)
|
||||
.values([(WebsocketConnectionIden::State, closed.as_str().into())])
|
||||
.cond_where(Expr::col(WebsocketConnectionIden::State).ne(closed.as_str()))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
let mut stmt = self.conn.prepare(sql.as_str())?;
|
||||
stmt.execute(&*params.as_params())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
25
src-tauri/yaak-models/src/queries/websocket_events.rs
Normal file
25
src-tauri/yaak-models/src/queries/websocket_events.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{
|
||||
WebsocketEvent,
|
||||
WebsocketEventIden,
|
||||
};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_websocket_event(&self, id: &str) -> Result<WebsocketEvent> {
|
||||
self.find_one(WebsocketEventIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_websocket_events(&self, connection_id: &str) -> Result<Vec<WebsocketEvent>> {
|
||||
self.find_many(WebsocketEventIden::ConnectionId, connection_id, None)
|
||||
}
|
||||
|
||||
pub fn upsert_websocket_event(
|
||||
&self,
|
||||
websocket_event: &WebsocketEvent,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketEvent> {
|
||||
self.upsert(websocket_event, source)
|
||||
}
|
||||
}
|
||||
51
src-tauri/yaak-models/src/queries/websocket_requests.rs
Normal file
51
src-tauri/yaak-models/src/queries/websocket_requests.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{WebsocketRequest, WebsocketRequestIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_websocket_request(&self, id: &str) -> Result<Option<WebsocketRequest>> {
|
||||
self.find_optional(WebsocketRequestIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_websocket_requests(&self, workspace_id: &str) -> Result<Vec<WebsocketRequest>> {
|
||||
self.find_many(WebsocketRequestIden::WorkspaceId, workspace_id, None)
|
||||
}
|
||||
|
||||
pub fn delete_websocket_request(
|
||||
&self,
|
||||
websocket_request: &WebsocketRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketRequest> {
|
||||
self.delete_all_websocket_connections_for_request(websocket_request.id.as_str(), source)?;
|
||||
self.delete(websocket_request, source)
|
||||
}
|
||||
|
||||
pub fn delete_websocket_request_by_id(
|
||||
&self,
|
||||
id: &str,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketRequest> {
|
||||
let request = self.get_websocket_request(id)?.unwrap();
|
||||
self.delete_websocket_request(&request, source)
|
||||
}
|
||||
|
||||
pub fn duplicate_websocket_request(
|
||||
&self,
|
||||
websocket_request: &WebsocketRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketRequest> {
|
||||
let mut websocket_request = websocket_request.clone();
|
||||
websocket_request.id = "".to_string();
|
||||
websocket_request.sort_priority = websocket_request.sort_priority + 0.001;
|
||||
self.upsert(&websocket_request, source)
|
||||
}
|
||||
|
||||
pub fn upsert_websocket_request(
|
||||
&self,
|
||||
websocket_request: &WebsocketRequest,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WebsocketRequest> {
|
||||
self.upsert(websocket_request, source)
|
||||
}
|
||||
}
|
||||
36
src-tauri/yaak-models/src/queries/workspace_metas.rs
Normal file
36
src-tauri/yaak-models/src/queries/workspace_metas.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{Workspace, WorkspaceMeta, WorkspaceMetaIden};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_workspace_meta(&self, workspace: &Workspace) -> Result<Option<WorkspaceMeta>> {
|
||||
self.find_optional(WorkspaceMetaIden::WorkspaceId, &workspace.id)
|
||||
}
|
||||
|
||||
pub fn get_or_create_workspace_meta(
|
||||
&self,
|
||||
workspace: &Workspace,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WorkspaceMeta> {
|
||||
let workspace_meta = self.get_workspace_meta(workspace)?;
|
||||
if let Some(workspace_meta) = workspace_meta {
|
||||
return Ok(workspace_meta);
|
||||
}
|
||||
|
||||
let workspace_meta = WorkspaceMeta {
|
||||
workspace_id: workspace.to_owned().id,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.upsert_workspace_meta(&workspace_meta, source)
|
||||
}
|
||||
|
||||
pub fn upsert_workspace_meta(
|
||||
&self,
|
||||
workspace_meta: &WorkspaceMeta,
|
||||
source: &UpdateSource,
|
||||
) -> Result<WorkspaceMeta> {
|
||||
self.upsert(workspace_meta, source)
|
||||
}
|
||||
}
|
||||
52
src-tauri/yaak-models/src/queries/workspaces.rs
Normal file
52
src-tauri/yaak-models/src/queries/workspaces.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::DbContext;
|
||||
use crate::models::{
|
||||
Folder, FolderIden, GrpcRequest, GrpcRequestIden, HttpRequest, HttpRequestIden,
|
||||
WebsocketRequest, WebsocketRequestIden, Workspace, WorkspaceIden,
|
||||
};
|
||||
use crate::queries_legacy::UpdateSource;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_workspace(&self, id: &str) -> Result<Workspace> {
|
||||
self.find_one(WorkspaceIden::Id, id)
|
||||
}
|
||||
|
||||
pub fn list_workspaces(&self) -> Result<Vec<Workspace>> {
|
||||
self.find_all()
|
||||
}
|
||||
|
||||
pub fn delete_workspace(
|
||||
&self,
|
||||
workspace: &Workspace,
|
||||
source: &UpdateSource,
|
||||
) -> Result<Workspace> {
|
||||
for folder in self.find_many::<Folder>(FolderIden::WorkspaceId, &workspace.id, None)? {
|
||||
self.delete_folder(&folder, source)?;
|
||||
}
|
||||
for request in
|
||||
self.find_many::<HttpRequest>(HttpRequestIden::WorkspaceId, &workspace.id, None)?
|
||||
{
|
||||
self.delete_http_request(&request, source)?;
|
||||
}
|
||||
for request in
|
||||
self.find_many::<GrpcRequest>(GrpcRequestIden::WorkspaceId, &workspace.id, None)?
|
||||
{
|
||||
self.delete_grpc_request(&request, source)?;
|
||||
}
|
||||
for request in
|
||||
self.find_many::<WebsocketRequest>(WebsocketRequestIden::FolderId, &workspace.id, None)?
|
||||
{
|
||||
self.delete_websocket_request(&request, source)?;
|
||||
}
|
||||
self.delete(workspace, source)
|
||||
}
|
||||
|
||||
pub fn delete_workspace_by_id(&self, id: &str, source: &UpdateSource) -> Result<Workspace> {
|
||||
let workspace = self.get_workspace(id)?;
|
||||
self.delete_workspace(&workspace, source)
|
||||
}
|
||||
|
||||
pub fn upsert_workspace(&self, w: &Workspace, source: &UpdateSource) -> Result<Workspace> {
|
||||
self.upsert(w, source)
|
||||
}
|
||||
}
|
||||
150
src-tauri/yaak-models/src/queries_legacy.rs
Normal file
150
src-tauri/yaak-models/src/queries_legacy.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use crate::error::Result;
|
||||
use crate::manager::QueryManagerExt;
|
||||
use crate::models::{AnyModel, Environment, Folder, GrpcRequest, HttpRequest, ModelType, WebsocketRequest, Workspace, WorkspaceIden};
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use log::warn;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, Listener, Runtime, WebviewWindow};
|
||||
use ts_rs::TS;
|
||||
|
||||
pub fn generate_model_id(model: ModelType) -> String {
|
||||
let id = generate_id();
|
||||
format!("{}_{}", model.id_prefix(), id)
|
||||
}
|
||||
|
||||
pub fn generate_id() -> String {
|
||||
let alphabet: [char; 57] = [
|
||||
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C',
|
||||
'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z',
|
||||
];
|
||||
|
||||
nanoid!(10, &alphabet)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
pub struct ModelPayload {
|
||||
pub model: AnyModel,
|
||||
pub update_source: UpdateSource,
|
||||
pub change: ModelChangeEvent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "snake_case", tag = "type")]
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
pub enum ModelChangeEvent {
|
||||
Upsert,
|
||||
Delete,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "snake_case", tag = "type")]
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
pub enum UpdateSource {
|
||||
Sync,
|
||||
Window { label: String },
|
||||
Plugin,
|
||||
Background,
|
||||
Import,
|
||||
}
|
||||
|
||||
impl UpdateSource {
|
||||
pub fn from_window<R: Runtime>(window: &WebviewWindow<R>) -> Self {
|
||||
Self::Window {
|
||||
label: window.label().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listen_to_model_delete<F, R>(app_handle: &AppHandle<R>, handler: F)
|
||||
where
|
||||
F: Fn(ModelPayload) + Send + 'static,
|
||||
R: Runtime,
|
||||
{
|
||||
app_handle.listen_any("deleted_model", move |e| {
|
||||
match serde_json::from_str(e.payload()) {
|
||||
Ok(payload) => handler(payload),
|
||||
Err(e) => {
|
||||
warn!("Failed to deserialize deleted model {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
pub fn listen_to_model_upsert<F, R>(app_handle: &AppHandle<R>, handler: F)
|
||||
where
|
||||
F: Fn(ModelPayload) + Send + 'static,
|
||||
R: Runtime,
|
||||
{
|
||||
app_handle.listen_any("upserted_model", move |e| {
|
||||
match serde_json::from_str(e.payload()) {
|
||||
Ok(payload) => handler(payload),
|
||||
Err(e) => {
|
||||
warn!("Failed to deserialize upserted model {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
pub struct WorkspaceExport {
|
||||
pub yaak_version: String,
|
||||
pub yaak_schema: i64,
|
||||
pub timestamp: NaiveDateTime,
|
||||
pub resources: BatchUpsertResult,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
pub struct BatchUpsertResult {
|
||||
pub workspaces: Vec<Workspace>,
|
||||
pub environments: Vec<Environment>,
|
||||
pub folders: Vec<Folder>,
|
||||
pub http_requests: Vec<HttpRequest>,
|
||||
pub grpc_requests: Vec<GrpcRequest>,
|
||||
pub websocket_requests: Vec<WebsocketRequest>,
|
||||
}
|
||||
|
||||
pub async fn get_workspace_export_resources<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
workspace_ids: Vec<&str>,
|
||||
include_environments: bool,
|
||||
) -> Result<WorkspaceExport> {
|
||||
let mut data = WorkspaceExport {
|
||||
yaak_version: app_handle.package_info().version.clone().to_string(),
|
||||
yaak_schema: 3,
|
||||
timestamp: Utc::now().naive_utc(),
|
||||
resources: BatchUpsertResult {
|
||||
workspaces: Vec::new(),
|
||||
environments: Vec::new(),
|
||||
folders: Vec::new(),
|
||||
http_requests: Vec::new(),
|
||||
grpc_requests: Vec::new(),
|
||||
websocket_requests: Vec::new(),
|
||||
},
|
||||
};
|
||||
|
||||
let db = app_handle.queries().connect().await?;
|
||||
for workspace_id in workspace_ids {
|
||||
data.resources.workspaces.push(db.find_one(WorkspaceIden::Id, workspace_id)?);
|
||||
data.resources.environments.append(&mut db.list_environments(workspace_id)?);
|
||||
data.resources.folders.append(&mut db.list_folders(workspace_id)?);
|
||||
data.resources.http_requests.append(&mut db.list_http_requests(workspace_id)?);
|
||||
data.resources.grpc_requests.append(&mut db.list_grpc_requests(workspace_id)?);
|
||||
data.resources.websocket_requests.append(&mut db.list_websocket_requests(workspace_id)?);
|
||||
}
|
||||
|
||||
// Nuke environments if we don't want them
|
||||
if !include_environments {
|
||||
data.resources.environments.clear();
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ use crate::events::{
|
||||
use crate::nodejs::start_nodejs_plugin_runtime;
|
||||
use crate::plugin_handle::PluginHandle;
|
||||
use crate::server_ws::PluginRuntimeServerWebsocket;
|
||||
use log::{info, warn};
|
||||
use log::{error, info, warn};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
@@ -25,9 +25,11 @@ use tauri::{AppHandle, Manager, Runtime, WebviewWindow};
|
||||
use tokio::fs::read_dir;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tokio::time::timeout;
|
||||
use yaak_models::queries::{generate_id, list_plugins};
|
||||
use tokio::time::{timeout, Instant};
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::queries_legacy::generate_id;
|
||||
use yaak_templates::error::Error::RenderError;
|
||||
use yaak_templates::error::Result as TemplateResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginManager {
|
||||
@@ -157,7 +159,8 @@ impl PluginManager {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let plugins = list_plugins(app_handle).await.unwrap_or_default();
|
||||
let plugins =
|
||||
app_handle.queries().connect().await.unwrap().list_plugins().unwrap_or_default();
|
||||
let installed_plugin_dirs: Vec<PluginCandidate> = plugins
|
||||
.iter()
|
||||
.map(|p| PluginCandidate {
|
||||
@@ -208,7 +211,7 @@ impl PluginManager {
|
||||
|
||||
// Boot the plugin
|
||||
let event = timeout(
|
||||
Duration::from_secs(2),
|
||||
Duration::from_secs(5),
|
||||
self.send_to_plugin_and_wait(
|
||||
window_context,
|
||||
&plugin_handle,
|
||||
@@ -239,12 +242,14 @@ impl PluginManager {
|
||||
app_handle: &AppHandle<R>,
|
||||
window_context: &WindowContext,
|
||||
) -> Result<()> {
|
||||
let start = Instant::now();
|
||||
let candidates = self.list_plugin_dirs(app_handle).await;
|
||||
for candidate in candidates.clone() {
|
||||
// First remove the plugin if it exists
|
||||
if let Some(plugin) = self.get_plugin_by_dir(candidate.dir.as_str()).await {
|
||||
if let Err(e) = self.remove_plugin(window_context, &plugin).await {
|
||||
warn!("Failed to remove plugin {} {e:?}", candidate.dir);
|
||||
error!("Failed to remove plugin {} {e:?}", candidate.dir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Err(e) = self
|
||||
@@ -255,15 +260,13 @@ impl PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
let plugins = self.plugins.lock().await;
|
||||
let names = plugins.iter().map(|p| p.dir.to_string()).collect::<Vec<String>>();
|
||||
info!(
|
||||
"Initialized all plugins:\n - {}",
|
||||
self.plugins
|
||||
.lock()
|
||||
.await
|
||||
.iter()
|
||||
.map(|p| p.dir.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n - "),
|
||||
"Initialized {} plugins in {:?}:\n - {}",
|
||||
plugins.len(),
|
||||
start.elapsed(),
|
||||
names.join("\n - "),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -598,7 +601,7 @@ impl PluginManager {
|
||||
fn_name: &str,
|
||||
args: HashMap<String, String>,
|
||||
purpose: RenderPurpose,
|
||||
) -> yaak_templates::error::Result<String> {
|
||||
) -> TemplateResult<String> {
|
||||
let req = CallTemplateFunctionRequest {
|
||||
name: fn_name.to_string(),
|
||||
args: CallTemplateFunctionArgs {
|
||||
@@ -615,13 +618,14 @@ impl PluginManager {
|
||||
let value = events.into_iter().find_map(|e| match e.payload {
|
||||
InternalEventPayload::CallTemplateFunctionResponse(CallTemplateFunctionResponse {
|
||||
value,
|
||||
}) => value,
|
||||
}) => Some(value),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
match value {
|
||||
None => Err(RenderError(format!("Template function not found {fn_name}"))),
|
||||
Some(v) => Ok(v),
|
||||
None => Err(RenderError(format!("Template function {fn_name}(…) not found "))),
|
||||
Some(Some(v)) => Ok(v), // Plugin returned string
|
||||
Some(None) => Ok("".to_string()), // Plugin returned null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"minimum": 1.0
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -111,7 +111,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -126,7 +126,8 @@ impl TryFrom<AnyModel> for SyncModel {
|
||||
AnyModel::WebsocketConnection(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::WebsocketEvent(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::WorkspaceMeta(m) => return Err(UnknownModel(m.model)),
|
||||
AnyModel::SyncState(m) => return Err(UnknownModel(m.model)),
|
||||
};
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,9 @@ use tokio::fs;
|
||||
use tokio::fs::File;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use ts_rs::TS;
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::models::{SyncState, WorkspaceMeta};
|
||||
use yaak_models::queries::{
|
||||
batch_upsert, delete_environment, delete_folder, delete_grpc_request, delete_http_request,
|
||||
delete_sync_state, delete_websocket_request, delete_workspace, get_workspace_export_resources,
|
||||
get_workspace_meta, list_sync_states_for_workspace, upsert_sync_state, upsert_workspace_meta,
|
||||
UpdateSource,
|
||||
};
|
||||
use yaak_models::queries_legacy::{get_workspace_export_resources, UpdateSource};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase", tag = "type")]
|
||||
@@ -115,12 +111,14 @@ pub(crate) async fn get_db_candidates<R: Runtime>(
|
||||
.into_iter()
|
||||
.map(|m| (m.id(), m))
|
||||
.collect();
|
||||
let sync_states: HashMap<_, _> =
|
||||
list_sync_states_for_workspace(app_handle, workspace_id, sync_dir)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|s| (s.model_id.clone(), s))
|
||||
.collect();
|
||||
let sync_states: HashMap<_, _> = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.list_sync_states_for_workspace(workspace_id, sync_dir)?
|
||||
.into_iter()
|
||||
.map(|s| (s.model_id.clone(), s))
|
||||
.collect();
|
||||
|
||||
// 1. Add candidates for models (created/modified/unmodified)
|
||||
let mut candidates: Vec<DbCandidate> = models
|
||||
@@ -442,41 +440,47 @@ pub(crate) async fn apply_sync_ops<R: Runtime>(
|
||||
});
|
||||
}
|
||||
|
||||
let upserted_models = batch_upsert(
|
||||
app_handle,
|
||||
workspaces_to_upsert,
|
||||
environments_to_upsert,
|
||||
folders_to_upsert,
|
||||
http_requests_to_upsert,
|
||||
grpc_requests_to_upsert,
|
||||
websocket_requests_to_upsert,
|
||||
&UpdateSource::Sync,
|
||||
)
|
||||
.await?;
|
||||
let upserted_models = app_handle
|
||||
.queries()
|
||||
.with_tx(|tx| {
|
||||
tx.batch_upsert(
|
||||
workspaces_to_upsert,
|
||||
environments_to_upsert,
|
||||
folders_to_upsert,
|
||||
http_requests_to_upsert,
|
||||
grpc_requests_to_upsert,
|
||||
websocket_requests_to_upsert,
|
||||
&UpdateSource::Sync,
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
|
||||
// Ensure we creat WorkspaceMeta models for each new workspace, with the appropriate sync dir
|
||||
let sync_dir_string = sync_dir.to_string_lossy().to_string();
|
||||
let db = app_handle.queries().connect().await?;
|
||||
for workspace in upserted_models.workspaces {
|
||||
let r = match get_workspace_meta(app_handle, &workspace).await {
|
||||
let r = match db.get_workspace_meta(&workspace) {
|
||||
Ok(Some(m)) => {
|
||||
if m.setting_sync_dir == Some(sync_dir_string.clone()) {
|
||||
// We don't need to update if unchanged
|
||||
continue;
|
||||
}
|
||||
let wm = WorkspaceMeta {
|
||||
setting_sync_dir: Some(sync_dir.to_string_lossy().to_string()),
|
||||
..m
|
||||
};
|
||||
upsert_workspace_meta(app_handle, wm, &UpdateSource::Sync).await
|
||||
db.upsert_workspace_meta(
|
||||
&WorkspaceMeta {
|
||||
setting_sync_dir: Some(sync_dir.to_string_lossy().to_string()),
|
||||
..m
|
||||
},
|
||||
&UpdateSource::Sync,
|
||||
)
|
||||
}
|
||||
Ok(None) => {
|
||||
let wm = WorkspaceMeta {
|
||||
Ok(None) => db.upsert_workspace_meta(
|
||||
&WorkspaceMeta {
|
||||
workspace_id: workspace_id.to_string(),
|
||||
setting_sync_dir: Some(sync_dir.to_string_lossy().to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
upsert_workspace_meta(app_handle, wm, &UpdateSource::Sync).await
|
||||
}
|
||||
},
|
||||
&UpdateSource::Sync,
|
||||
),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
@@ -527,7 +531,7 @@ pub(crate) async fn apply_sync_state_ops<R: Runtime>(
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..Default::default()
|
||||
};
|
||||
upsert_sync_state(app_handle, sync_state).await?;
|
||||
app_handle.queries().connect().await?.upsert_sync_state(&sync_state)?;
|
||||
}
|
||||
SyncStateOp::Update {
|
||||
state: sync_state,
|
||||
@@ -541,10 +545,10 @@ pub(crate) async fn apply_sync_state_ops<R: Runtime>(
|
||||
flushed_at: Utc::now().naive_utc(),
|
||||
..sync_state
|
||||
};
|
||||
upsert_sync_state(app_handle, sync_state).await?;
|
||||
app_handle.queries().connect().await?.upsert_sync_state(&sync_state)?;
|
||||
}
|
||||
SyncStateOp::Delete { state } => {
|
||||
delete_sync_state(app_handle, state.id.as_str()).await?;
|
||||
app_handle.queries().connect().await?.delete_sync_state(&state)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -557,24 +561,25 @@ fn derive_model_filename(m: &SyncModel) -> PathBuf {
|
||||
}
|
||||
|
||||
async fn delete_model<R: Runtime>(app_handle: &AppHandle<R>, model: &SyncModel) -> Result<()> {
|
||||
let db = app_handle.queries().connect().await?;
|
||||
match model {
|
||||
SyncModel::Workspace(m) => {
|
||||
delete_workspace(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_workspace(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
SyncModel::Environment(m) => {
|
||||
delete_environment(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_environment(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
SyncModel::Folder(m) => {
|
||||
delete_folder(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_folder(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
SyncModel::HttpRequest(m) => {
|
||||
delete_http_request(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_http_request(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
SyncModel::GrpcRequest(m) => {
|
||||
delete_grpc_request(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_grpc_request(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
SyncModel::WebsocketRequest(m) => {
|
||||
delete_websocket_request(app_handle, m.id.as_str(), &UpdateSource::Sync).await?;
|
||||
db.delete_websocket_request(&m, &UpdateSource::Sync)?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"minimum": 1.0
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -111,7 +111,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use <h4> headings in markdown content for Tauri documentation generation purposes.",
|
||||
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -10,15 +10,12 @@ use tokio::sync::{mpsc, Mutex};
|
||||
use tokio_tungstenite::tungstenite::http::HeaderValue;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use yaak_http::apply_path_placeholders;
|
||||
use yaak_models::manager::QueryManagerExt;
|
||||
use yaak_models::models::{
|
||||
HttpResponseHeader, WebsocketConnection, WebsocketConnectionState, WebsocketEvent,
|
||||
WebsocketEventType, WebsocketRequest,
|
||||
};
|
||||
use yaak_models::queries;
|
||||
use yaak_models::queries::{
|
||||
get_base_environment, get_cookie_jar, get_environment, get_websocket_connection,
|
||||
get_websocket_request, upsert_websocket_connection, upsert_websocket_event, UpdateSource,
|
||||
};
|
||||
use yaak_models::queries_legacy::UpdateSource;
|
||||
use yaak_plugins::events::{
|
||||
CallHttpAuthenticationRequest, HttpHeader, RenderPurpose, WindowContext,
|
||||
};
|
||||
@@ -31,8 +28,11 @@ pub(crate) async fn upsert_request<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<WebsocketRequest> {
|
||||
Ok(queries::upsert_websocket_request(&app_handle, request, &UpdateSource::from_window(&window))
|
||||
.await?)
|
||||
Ok(app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.upsert_websocket_request(&request, &UpdateSource::from_window(&window))?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -41,12 +41,9 @@ pub(crate) async fn duplicate_request<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<WebsocketRequest> {
|
||||
Ok(queries::duplicate_websocket_request(
|
||||
&app_handle,
|
||||
request_id,
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await?)
|
||||
let db = app_handle.queries().connect().await?;
|
||||
let request = db.get_websocket_request(request_id)?.unwrap();
|
||||
Ok(db.duplicate_websocket_request(&request, &UpdateSource::from_window(&window))?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -55,7 +52,11 @@ pub(crate) async fn delete_request<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<WebsocketRequest> {
|
||||
Ok(queries::delete_websocket_request(&app_handle, request_id, &UpdateSource::from_window(&window)).await?)
|
||||
Ok(app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.delete_websocket_request_by_id(request_id, &UpdateSource::from_window(&window))?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -64,8 +65,11 @@ pub(crate) async fn delete_connection<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<WebsocketConnection> {
|
||||
Ok(queries::delete_websocket_connection(&app_handle, connection_id, &UpdateSource::from_window(&window))
|
||||
.await?)
|
||||
Ok(app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.delete_websocket_connection_by_id(connection_id, &UpdateSource::from_window(&window))?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -74,8 +78,10 @@ pub(crate) async fn delete_connections<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<()> {
|
||||
Ok(queries::delete_all_websocket_connections(&app_handle, request_id, &UpdateSource::from_window(&window))
|
||||
.await?)
|
||||
Ok(app_handle.queries().connect().await?.delete_all_websocket_connections_for_request(
|
||||
request_id,
|
||||
&UpdateSource::from_window(&window),
|
||||
)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -83,7 +89,7 @@ pub(crate) async fn list_events<R: Runtime>(
|
||||
connection_id: &str,
|
||||
app_handle: AppHandle<R>,
|
||||
) -> Result<Vec<WebsocketEvent>> {
|
||||
Ok(queries::list_websocket_events(&app_handle, connection_id).await?)
|
||||
Ok(app_handle.queries().connect().await?.list_websocket_events(connection_id)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -91,7 +97,7 @@ pub(crate) async fn list_requests<R: Runtime>(
|
||||
workspace_id: &str,
|
||||
app_handle: AppHandle<R>,
|
||||
) -> Result<Vec<WebsocketRequest>> {
|
||||
Ok(queries::list_websocket_requests(&app_handle, workspace_id).await?)
|
||||
Ok(app_handle.queries().connect().await?.list_websocket_requests(workspace_id)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -99,7 +105,11 @@ pub(crate) async fn list_connections<R: Runtime>(
|
||||
workspace_id: &str,
|
||||
app_handle: AppHandle<R>,
|
||||
) -> Result<Vec<WebsocketConnection>> {
|
||||
Ok(queries::list_websocket_connections_for_workspace(&app_handle, workspace_id).await?)
|
||||
Ok(app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.list_websocket_connections_for_workspace(workspace_id)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -110,16 +120,23 @@ pub(crate) async fn send<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
ws_manager: State<'_, Mutex<WebsocketManager>>,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let connection = get_websocket_connection(&app_handle, connection_id).await?;
|
||||
let unrendered_request = get_websocket_request(&app_handle, &connection.request_id)
|
||||
.await?
|
||||
.ok_or(GenericError("WebSocket Request not found".to_string()))?;
|
||||
let (connection, unrendered_request) = {
|
||||
let db = app_handle.queries().connect().await?;
|
||||
let connection = db.get_websocket_connection(connection_id)?;
|
||||
let unrendered_request = db
|
||||
.get_websocket_request(&connection.request_id)?
|
||||
.ok_or(GenericError("WebSocket Request not found".to_string()))?;
|
||||
(connection, unrendered_request)
|
||||
};
|
||||
let environment = match environment_id {
|
||||
Some(id) => Some(get_environment(&app_handle, id).await?),
|
||||
Some(id) => Some(app_handle.queries().connect().await?.get_environment(id)?),
|
||||
None => None,
|
||||
};
|
||||
let base_environment =
|
||||
get_base_environment(&app_handle, &unrendered_request.workspace_id).await?;
|
||||
let base_environment = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_base_environment(&unrendered_request.workspace_id)?;
|
||||
let request = render_request(
|
||||
&unrendered_request,
|
||||
&base_environment,
|
||||
@@ -135,9 +152,8 @@ pub(crate) async fn send<R: Runtime>(
|
||||
let mut ws_manager = ws_manager.lock().await;
|
||||
ws_manager.send(&connection.id, Message::Text(request.message.clone().into())).await?;
|
||||
|
||||
upsert_websocket_event(
|
||||
&app_handle,
|
||||
WebsocketEvent {
|
||||
app_handle.queries().connect().await?.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
@@ -147,9 +163,7 @@ pub(crate) async fn send<R: Runtime>(
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
Ok(connection)
|
||||
}
|
||||
@@ -161,17 +175,17 @@ pub(crate) async fn close<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
ws_manager: State<'_, Mutex<WebsocketManager>>,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let connection = get_websocket_connection(&app_handle, connection_id).await?;
|
||||
let connection = upsert_websocket_connection(
|
||||
&app_handle,
|
||||
&WebsocketConnection {
|
||||
state: WebsocketConnectionState::Closing,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let connection = {
|
||||
let db = app_handle.queries().connect().await?;
|
||||
let connection = db.get_websocket_connection(connection_id)?;
|
||||
db.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
state: WebsocketConnectionState::Closing,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)?
|
||||
};
|
||||
|
||||
let mut ws_manager = ws_manager.lock().await;
|
||||
if let Err(e) = ws_manager.close(&connection.id).await {
|
||||
@@ -191,15 +205,21 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
ws_manager: State<'_, Mutex<WebsocketManager>>,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let unrendered_request = get_websocket_request(&app_handle, request_id)
|
||||
let unrendered_request = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_websocket_request(request_id)?
|
||||
.ok_or(GenericError("Failed to find GRPC request".to_string()))?;
|
||||
let environment = match environment_id {
|
||||
Some(id) => Some(get_environment(&app_handle, id).await?),
|
||||
Some(id) => Some(app_handle.queries().connect().await?.get_environment(id)?),
|
||||
None => None,
|
||||
};
|
||||
let base_environment =
|
||||
get_base_environment(&app_handle, &unrendered_request.workspace_id).await?;
|
||||
let base_environment = app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await?
|
||||
.get_base_environment(&unrendered_request.workspace_id)?;
|
||||
let request = render_request(
|
||||
&unrendered_request,
|
||||
&base_environment,
|
||||
@@ -242,20 +262,18 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
|
||||
// TODO: Handle cookies
|
||||
let _cookie_jar = match cookie_jar_id {
|
||||
Some(id) => Some(get_cookie_jar(&app_handle, id).await?),
|
||||
Some(id) => Some(app_handle.queries().connect().await?.get_cookie_jar(id)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let connection = upsert_websocket_connection(
|
||||
&app_handle,
|
||||
let connection = app_handle.queries().connect().await?.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await?;
|
||||
)?;
|
||||
|
||||
let (receive_tx, mut receive_rx) = mpsc::channel::<Message>(128);
|
||||
let mut ws_manager = ws_manager.lock().await;
|
||||
@@ -278,22 +296,19 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Ok(upsert_websocket_connection(
|
||||
&app_handle,
|
||||
return Ok(app_handle.queries().connect().await?.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
error: Some(format!("{e:?}")),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await?);
|
||||
)?);
|
||||
}
|
||||
};
|
||||
|
||||
upsert_websocket_event(
|
||||
&app_handle,
|
||||
WebsocketEvent {
|
||||
app_handle.queries().connect().await?.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
@@ -302,9 +317,7 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
let response_headers = response
|
||||
.headers()
|
||||
@@ -315,8 +328,7 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
})
|
||||
.collect::<Vec<HttpResponseHeader>>();
|
||||
|
||||
let connection = upsert_websocket_connection(
|
||||
&app_handle,
|
||||
let connection = app_handle.queries().connect().await?.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
state: WebsocketConnectionState::Connected,
|
||||
headers: response_headers,
|
||||
@@ -325,8 +337,7 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await?;
|
||||
)?;
|
||||
|
||||
{
|
||||
let connection_id = connection.id.clone();
|
||||
@@ -340,59 +351,68 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
has_written_close = true;
|
||||
}
|
||||
|
||||
upsert_websocket_event(
|
||||
&app_handle,
|
||||
WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: match message {
|
||||
Message::Text(_) => WebsocketEventType::Text,
|
||||
Message::Binary(_) => WebsocketEventType::Binary,
|
||||
Message::Ping(_) => WebsocketEventType::Ping,
|
||||
Message::Pong(_) => WebsocketEventType::Pong,
|
||||
Message::Close(_) => WebsocketEventType::Close,
|
||||
// Raw frame will never happen during a read
|
||||
Message::Frame(_) => WebsocketEventType::Frame,
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: match message {
|
||||
Message::Text(_) => WebsocketEventType::Text,
|
||||
Message::Binary(_) => WebsocketEventType::Binary,
|
||||
Message::Ping(_) => WebsocketEventType::Ping,
|
||||
Message::Pong(_) => WebsocketEventType::Pong,
|
||||
Message::Close(_) => WebsocketEventType::Close,
|
||||
// Raw frame will never happen during a read
|
||||
Message::Frame(_) => WebsocketEventType::Frame,
|
||||
},
|
||||
message: message.into_data().into(),
|
||||
..Default::default()
|
||||
},
|
||||
message: message.into_data().into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
info!("Websocket connection closed");
|
||||
if !has_written_close {
|
||||
upsert_websocket_event(
|
||||
&app_handle,
|
||||
WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: WebsocketEventType::Close,
|
||||
..Default::default()
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: WebsocketEventType::Close,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
app_handle
|
||||
.queries()
|
||||
.connect()
|
||||
.await
|
||||
.unwrap()
|
||||
.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
upsert_websocket_connection(
|
||||
&app_handle,
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window(&window),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
|
||||
},
|
||||
[activeRequestId, setActiveTabs],
|
||||
);
|
||||
console.log("ACTIVE RESPONSE", activeResponse);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -25,7 +25,7 @@ export function useCreateHttpRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invokeCmd<HttpRequest>('cmd_create_http_request', {
|
||||
return invokeCmd<HttpRequest>('cmd_upsert_http_request', {
|
||||
request: { workspaceId, ...patch },
|
||||
});
|
||||
},
|
||||
|
||||
@@ -178,7 +178,6 @@ export function removeModelByKv(model: KeyValue) {
|
||||
}
|
||||
|
||||
function shouldIgnoreModel({ model, updateSource }: ModelPayload) {
|
||||
console.log('HELLO', updateSource);
|
||||
// Never ignore updates from non-user sources
|
||||
if (updateSource.type !== 'window') {
|
||||
return false;
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useUpdateAnyHttpRequest() {
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
return invokeCmd<HttpRequest>('cmd_update_http_request', { request: patchedRequest });
|
||||
return invokeCmd<HttpRequest>('cmd_upsert_http_request', { request: patchedRequest });
|
||||
},
|
||||
onSuccess: async (request) => {
|
||||
setHttpRequests(updateModelList(request));
|
||||
|
||||
@@ -8,7 +8,6 @@ type TauriCmd =
|
||||
| 'cmd_create_cookie_jar'
|
||||
| 'cmd_create_environment'
|
||||
| 'cmd_create_grpc_request'
|
||||
| 'cmd_create_http_request'
|
||||
| 'cmd_curl_to_request'
|
||||
| 'cmd_delete_all_grpc_connections'
|
||||
| 'cmd_delete_all_http_responses'
|
||||
@@ -75,7 +74,7 @@ type TauriCmd =
|
||||
| 'cmd_update_environment'
|
||||
| 'cmd_update_folder'
|
||||
| 'cmd_update_grpc_request'
|
||||
| 'cmd_update_http_request'
|
||||
| 'cmd_upsert_http_request'
|
||||
| 'cmd_update_settings'
|
||||
| 'cmd_update_workspace'
|
||||
| 'cmd_update_workspace_meta';
|
||||
|
||||
Reference in New Issue
Block a user