mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-02-17 08:07:46 +01:00
Compare commits
18 Commits
v2024.11.0
...
v2024.11.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9f397e04a | ||
|
|
57c3a86799 | ||
|
|
52ac41b0c6 | ||
|
|
741ccbe741 | ||
|
|
2ecd86da78 | ||
|
|
30e4e7665a | ||
|
|
516dfd1f19 | ||
|
|
0cd08499aa | ||
|
|
c652df82a3 | ||
|
|
c8342fb0a9 | ||
|
|
d0b59a0fb4 | ||
|
|
6f50f35519 | ||
|
|
4e775b2b49 | ||
|
|
e77a9e5d44 | ||
|
|
a381e44d8c | ||
|
|
4acf0969e8 | ||
|
|
30c4178269 | ||
|
|
dffe6e0a16 |
@@ -1,4 +1,4 @@
|
||||
# [Yaak API Client](https://yaak.app)
|
||||
# Yaak API Client
|
||||
|
||||
Yaak is a desktop API client for organizing and executing REST, GraphQL, and gRPC
|
||||
requests. It's built using [Tauri](https://tauri.app), Rust, and ReactJS.
|
||||
|
||||
88
package-lock.json
generated
88
package-lock.json
generated
@@ -18,7 +18,7 @@
|
||||
"src-web"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.0.2",
|
||||
"@tauri-apps/cli": "^2.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
||||
"@typescript-eslint/parser": "^8.5.0",
|
||||
"eslint": "^8",
|
||||
@@ -2689,9 +2689,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.2.tgz",
|
||||
"integrity": "sha512-R4ontHZvXORArERAHIidp5zRfZEshZczTiK+poslBv7AGKpQZoMw+E49zns7mOmP64i2Cq9Ci0pJvi4Rm8Okzw==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.3.tgz",
|
||||
"integrity": "sha512-JwEyhc5BAVpn4E8kxzY/h7+bVOiXQdudR1r3ODMfyyumZBfgIWqpD/WuTcPq6Yjchju1BSS+80jAE/oYwI/RKg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"bin": {
|
||||
@@ -2705,22 +2705,22 @@
|
||||
"url": "https://opencollective.com/tauri"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tauri-apps/cli-darwin-arm64": "2.0.2",
|
||||
"@tauri-apps/cli-darwin-x64": "2.0.2",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.2",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.0.2",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.0.2",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.0.2",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.0.2",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.0.2",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.0.2",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.0.2"
|
||||
"@tauri-apps/cli-darwin-arm64": "2.0.3",
|
||||
"@tauri-apps/cli-darwin-x64": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.0.3",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.0.3",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.0.3",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.0.3",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.0.3",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.2.tgz",
|
||||
"integrity": "sha512-B+/a8Q6wAqmB4A4HVeK0oQP5TdQGKW60ZLOI9O2ktH2HPr9ETr3XkwXPuJ2uAOuGEgtRZHBgFOIgG000vMnKlg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.3.tgz",
|
||||
"integrity": "sha512-jIsbxGWS+As1ZN7umo90nkql/ZAbrDK0GBT6UsgHSz5zSwwArICsZFFwE1pLZip5yoiV5mn3TGG2c1+v+0puzQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2735,9 +2735,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.2.tgz",
|
||||
"integrity": "sha512-kaurhn6XT4gAVCPAQSSHl/CHFxTS0ljc47N7iGTSlYJ03sCWPRZeNuVa/bn6rolz9MA2JfnRnFqB1pUL6jzp9Q==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.3.tgz",
|
||||
"integrity": "sha512-ROITHtLTA1muyrwgyuwyasmaLCGtT4as/Kd1kerXaSDtFcYrnxiM984ZD0+FDUEDl5BgXtYa/sKKkKQFjgmM0A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2752,9 +2752,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.2.tgz",
|
||||
"integrity": "sha512-bVrofjlacMxmGMcqK18iBW05tsZXOd19/MnqruFFcHSVjvkGGIXHMtUbMXnZNXBPkHDsnfytNtkY9SZGfCFaBA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.3.tgz",
|
||||
"integrity": "sha512-bQ3EZwCFfrLg/ZQ2I8sLuifSxESz4TP56SleTkKsPtTIZgNnKpM88PRDz4neiRroHVOq8NK0X276qi9LjGcXPw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2769,9 +2769,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.2.tgz",
|
||||
"integrity": "sha512-7XCBn0TTBVQGnV42dXcbHPLg/9W8kJoVzuliIozvNGyRWxfXqDbQYzpI48HUQG3LgHMabcw8+pVZAfGhevLrCA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.3.tgz",
|
||||
"integrity": "sha512-aLfAA8P9OTErVUk3sATxtXqpAtlfDPMPp4fGjDysEELG/MyekGhmh2k/kG/i32OdPeCfO+Nr37wJksARJKubGw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2786,9 +2786,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.2.tgz",
|
||||
"integrity": "sha512-1xi2SreGVlpAL68MCsDUY63rdItUdPZreXIAcOVqvUehcJRYOa1XGSBhrV0YXRgZeh0AtKC19z6PRzcv4rosZA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.3.tgz",
|
||||
"integrity": "sha512-I4MVD7nf6lLLRmNQPpe5beEIFM6q7Zkmh77ROA5BNu/+vHNL5kiTMD+bmd10ZL2r753A6pO7AvqkIxcBuIl0tg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2803,9 +2803,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.2.tgz",
|
||||
"integrity": "sha512-WVjwYzPWFqZVg1fx6KSU5w47Q0VbMyaCp34qs5EcS8EIU0/RnofdzqUoOYqvgGVgNgoz7Pj5dXK2SkS8BHXMmA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.3.tgz",
|
||||
"integrity": "sha512-C6Jkx2zZGKkoi+sg5FK9GoH/0EvAaOgrZfF5azV5EALGba46g7VpWcZgp9zFUd7K2IzTi+0OOY8TQ2OVfKZgew==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2820,9 +2820,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.2.tgz",
|
||||
"integrity": "sha512-h5miE2mctgaQNn/BbG9o1pnJcrx+VGBi2A6JFqGu934lFgSV5+s28M8Gc8AF2JgFH4hQV4IuMkeSw8Chu5Dodg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.3.tgz",
|
||||
"integrity": "sha512-qi4ghmTfSAl+EEUDwmwI9AJUiOLNSmU1RgiGgcPRE+7A/W+Am9UnxYySAiRbB/gJgTl9sj/pqH5Y9duP1/sqHg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2837,9 +2837,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-2b8oO0+dYonahG5PfA/zoq0zlafLclfmXgqoWDZ++UiPtQHJNpNeEQ8GWbSFKGHQ494Jo6jHvazOojGRE1kqAg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-UXxHkYmFesC97qVmZre4vY7oDxRDtC2OeKNv0bH+iSnuUp/ROxzJYGyaelnv9Ybvgl4YVqDCnxgB28qMM938TA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2854,9 +2854,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-axgICLunFi0To3EibdCBgbST5RocsSmtM4c04+CbcX8WQQosJ9ziWlCSrrOTRr+gJERAMSvEyVUS98f6bWMw9A==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-D+xoaa35RGlkXDpnL5uDTpj29untuC5Wp6bN9snfgFDagD0wnFfC8+2ZQGu16bD0IteWqDI0OSoIXhNvy+F+wg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2871,9 +2871,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-JR17cM6+DyExZRgpXr2/DdqvcFYi/EKvQt8dI5R1/uQoesWd8jeNnrU7c1FG1Zmw9+pTzDztsNqEKsrNq2sNIg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-eWV9XWb4dSYHXl13OtYWLjX1JHphUEkHkkGwJrhr8qFBm7RbxXxQvrsUEprSi51ug/dwJenjJgM4zR8By4htfw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"tauri-before-dev": "npm run --workspaces --if-present dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.0.2",
|
||||
"@tauri-apps/cli": "^2.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
||||
"@typescript-eslint/parser": "^8.5.0",
|
||||
"eslint": "^8",
|
||||
|
||||
12
src-tauri/Cargo.lock
generated
12
src-tauri/Cargo.lock
generated
@@ -6095,9 +6095,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.0.3"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd96d46534b10765ce0c6208f9451d98ea38636364a41b272d3610c70dd0e4c3"
|
||||
checksum = "44438500b50708bfc1e6083844e135d1b516325aae58710dcd8fb67e050ae87c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -6406,9 +6406,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.1.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaac63b65df8e85570993eaf93ae1dd73a6fb66d8bd99674ce65f41dc3c63e7d"
|
||||
checksum = "1431602bcc71f2f840ad623915c9842ecc32999b867c4a787d975a17a9625cc6"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http 1.1.0",
|
||||
@@ -7848,9 +7848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.46.0"
|
||||
version = "0.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469a3765ecc3e8aa9ccdf3c5a52c82697ec03037cd60494488763880d31a1b3a"
|
||||
checksum = "2f8c948dc5f7c23bd93ba03b85b7f679852589bb78e150424d993171e4ef7b73"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2",
|
||||
|
||||
@@ -66,4 +66,4 @@ eventsource-client = { git = "https://github.com/yaakapp/rust-eventsource-client
|
||||
yaak_models = { path = "yaak_models" }
|
||||
yaak_plugin_runtime = { path = "yaak_plugin_runtime" }
|
||||
tauri-plugin-shell = "2.0.1"
|
||||
tauri = { version = "2.0.3", features = ["devtools", "protocol-asset"] }
|
||||
tauri = { version = "2.0.4", features = ["devtools", "protocol-asset"] }
|
||||
|
||||
@@ -406,9 +406,9 @@ pub async fn send_http_request<R: Runtime>(
|
||||
let base_dir = dir.join("responses");
|
||||
create_dir_all(base_dir.clone()).await.expect("Failed to create responses dir");
|
||||
let body_path = if response_id.is_empty() {
|
||||
base_dir.join(response_id.clone())
|
||||
} else {
|
||||
base_dir.join(uuid::Uuid::new_v4().to_string())
|
||||
} else {
|
||||
base_dir.join(response_id.clone())
|
||||
};
|
||||
|
||||
{
|
||||
@@ -459,11 +459,11 @@ pub async fn send_http_request<R: Runtime>(
|
||||
}
|
||||
match chunk {
|
||||
Ok(Some(bytes)) => {
|
||||
let mut r = response.lock().await;
|
||||
r.elapsed = start.elapsed().as_millis() as i32;
|
||||
f.write_all(&bytes).await.expect("Failed to write to file");
|
||||
f.flush().await.expect("Failed to flush file");
|
||||
written_bytes += bytes.len();
|
||||
let mut r = response.lock().await;
|
||||
r.elapsed = start.elapsed().as_millis() as i32;
|
||||
r.content_length = Some(written_bytes as i32);
|
||||
update_response_if_id(&window, &r)
|
||||
.await
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -72,9 +72,6 @@
|
||||
"rpm"
|
||||
],
|
||||
"createUpdaterArtifacts": "v1Compatible",
|
||||
"iOS": {
|
||||
"developmentTeam": "7PU3P6ELJ8"
|
||||
},
|
||||
"macOS": {
|
||||
"minimumSystemVersion": "13.0",
|
||||
"exceptionDomain": "",
|
||||
|
||||
@@ -288,7 +288,8 @@ var SUPPORTED_ARGS = [
|
||||
// Request method
|
||||
DATA_FLAGS
|
||||
].flatMap((v) => v);
|
||||
function pluginHookImport(ctx, rawData) {
|
||||
var BOOL_FLAGS = ["G", "get", "digest"];
|
||||
function pluginHookImport(_ctx, rawData) {
|
||||
if (!rawData.match(/^\s*curl /)) {
|
||||
return null;
|
||||
}
|
||||
@@ -359,10 +360,11 @@ function importCommand(parseEntries, workspaceId) {
|
||||
}
|
||||
let value;
|
||||
const nextEntry = parseEntries[i + 1];
|
||||
const hasValue = !BOOL_FLAGS.includes(name);
|
||||
if (isSingleDash && name.length > 1) {
|
||||
value = name.slice(1);
|
||||
name = name.slice(0, 1);
|
||||
} else if (typeof nextEntry === "string" && !nextEntry.startsWith("-")) {
|
||||
} else if (typeof nextEntry === "string" && hasValue && !nextEntry.startsWith("-")) {
|
||||
value = nextEntry;
|
||||
i++;
|
||||
} else {
|
||||
|
||||
55
src-tauri/vendored/plugins/template-function-fs/build/index.js
generated
Normal file
55
src-tauri/vendored/plugins/template-function-fs/build/index.js
generated
Normal file
@@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
plugin: () => plugin
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
var import_node_fs = __toESM(require("node:fs"));
|
||||
var plugin = {
|
||||
templateFunctions: [{
|
||||
name: "fs.readFile",
|
||||
description: "Read the contents of a file as utf-8",
|
||||
args: [{ title: "Select File", type: "file", name: "path", label: "File" }],
|
||||
async onRender(_ctx, args) {
|
||||
if (!args.values.path) return null;
|
||||
try {
|
||||
return import_node_fs.default.promises.readFile(args.values.path, "utf-8");
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}]
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
plugin
|
||||
});
|
||||
9
src-tauri/vendored/plugins/template-function-fs/package.json
generated
Normal file
9
src-tauri/vendored/plugins/template-function-fs/package.json
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "@yaakapp/template-function-fs",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.ts",
|
||||
"dev": "yaakcli dev ./src/index.js"
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ var algorithms = ["md5", "sha1", "sha256", "sha512"];
|
||||
var plugin = {
|
||||
templateFunctions: algorithms.map((algorithm) => ({
|
||||
name: `hash.${algorithm}`,
|
||||
description: "Hash a value to its hexidecimal representation",
|
||||
args: [
|
||||
{
|
||||
name: "input",
|
||||
|
||||
@@ -26,24 +26,21 @@ module.exports = __toCommonJS(src_exports);
|
||||
var plugin = {
|
||||
templateFunctions: [{
|
||||
name: "prompt.text",
|
||||
description: "Prompt the user for input when sending a request",
|
||||
args: [
|
||||
{ type: "text", name: "title", label: "Title" },
|
||||
{ type: "text", name: "label", label: "Label", optional: true },
|
||||
{ type: "text", name: "defaultValue", label: "Default Value", optional: true },
|
||||
{ type: "text", name: "placeholder", label: "Placeholder", optional: true }
|
||||
],
|
||||
async onRender(ctx, args) {
|
||||
console.log("PROMPT", args);
|
||||
if (args.purpose !== "send") return null;
|
||||
const value = await ctx.prompt.text({
|
||||
return await ctx.prompt.text({
|
||||
id: `prompt-${args.values.label}`,
|
||||
label: args.values.label ?? "",
|
||||
label: args.values.title ?? "",
|
||||
title: args.values.title ?? "",
|
||||
defaultValue: args.values.defaultValue,
|
||||
placeholder: args.values.placeholder
|
||||
});
|
||||
console.log("VALUE", value);
|
||||
return value;
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
@@ -8837,6 +8837,7 @@ var plugin = {
|
||||
templateFunctions: [
|
||||
{
|
||||
name: "response.header",
|
||||
description: "Read the value of a response header, by name",
|
||||
args: [
|
||||
requestArg,
|
||||
{
|
||||
@@ -8863,6 +8864,7 @@ var plugin = {
|
||||
},
|
||||
{
|
||||
name: "response.body.path",
|
||||
description: "Access a field of the response body using JsonPath or XPath",
|
||||
aliases: ["response"],
|
||||
args: [
|
||||
requestArg,
|
||||
@@ -8901,6 +8903,34 @@ var plugin = {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "response.body.raw",
|
||||
description: "Access the entire response body, as text",
|
||||
aliases: ["response"],
|
||||
args: [
|
||||
requestArg,
|
||||
behaviorArg
|
||||
],
|
||||
async onRender(ctx, args) {
|
||||
if (!args.values.request) return null;
|
||||
const response = await getResponse(ctx, {
|
||||
requestId: args.values.request,
|
||||
purpose: args.purpose,
|
||||
behavior: args.values.behavior ?? null
|
||||
});
|
||||
if (response == null) return null;
|
||||
if (response.bodyPath == null) {
|
||||
return null;
|
||||
}
|
||||
let body;
|
||||
try {
|
||||
body = (0, import_node_fs.readFileSync)(response.bodyPath, "utf-8");
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -509,7 +509,7 @@ pub async fn get_grpc_connection<R: Runtime>(
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_grpc_connections<R: Runtime>(
|
||||
pub async fn list_grpc_connections_for_workspace<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<GrpcConnection>> {
|
||||
@@ -573,6 +573,16 @@ pub async fn delete_all_grpc_connections<R: Runtime>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_all_grpc_connections_for_workspace<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<()> {
|
||||
for r in list_grpc_connections_for_workspace(window, workspace_id).await? {
|
||||
delete_grpc_connection(window, &r.id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn upsert_grpc_event<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
event: &GrpcEvent,
|
||||
@@ -1433,7 +1443,17 @@ pub async fn delete_all_http_responses_for_request<R: Runtime>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_http_responses<R: Runtime>(
|
||||
pub async fn delete_all_http_responses_for_workspace<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<()> {
|
||||
for r in list_http_responses_for_workspace(window, workspace_id, None).await? {
|
||||
delete_http_response(window, &r.id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_http_responses_for_workspace<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
limit: Option<i64>,
|
||||
|
||||
@@ -273,9 +273,9 @@ impl PluginManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||
pub async fn subscribe(&self, label: &str) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||
let (tx, rx) = mpsc::channel(128);
|
||||
let rx_id = generate_id();
|
||||
let rx_id = format!("{label}_{}", generate_id());
|
||||
self.subscribers.lock().await.insert(rx_id.clone(), tx);
|
||||
(rx_id, rx)
|
||||
}
|
||||
@@ -362,7 +362,8 @@ impl PluginManager {
|
||||
payload: &InternalEventPayload,
|
||||
plugins: Vec<PluginHandle>,
|
||||
) -> Result<Vec<InternalEvent>> {
|
||||
let (rx_id, mut rx) = self.subscribe().await;
|
||||
let label = format!("wait[{}]", plugins.len());
|
||||
let (rx_id, mut rx) = self.subscribe(label.as_str()).await;
|
||||
|
||||
// 1. Build the events with IDs and everything
|
||||
let events_to_send = plugins
|
||||
@@ -557,9 +558,9 @@ impl PluginManager {
|
||||
content_type: &str,
|
||||
) -> Result<FilterResponse> {
|
||||
let plugin_name = if content_type.to_lowercase().contains("json") {
|
||||
"filter-jsonpath"
|
||||
"@yaakapp/filter-jsonpath"
|
||||
} else {
|
||||
"filter-xpath"
|
||||
"@yaakapp/filter-xpath"
|
||||
};
|
||||
|
||||
let plugin = self
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { lazy } from 'react';
|
||||
import { createBrowserRouter, Navigate, RouterProvider, useParams } from 'react-router-dom';
|
||||
import { routePaths, useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useGenerateThemeCss } from '../hooks/useGenerateThemeCss';
|
||||
import { useSyncFontSizeSetting } from '../hooks/useSyncFontSizeSetting';
|
||||
import { useSyncModelStores } from '../hooks/useSyncModelStores';
|
||||
import { useSyncZoomSetting } from '../hooks/useSyncZoomSetting';
|
||||
import { DefaultLayout } from './DefaultLayout';
|
||||
import { RedirectToLatestWorkspace } from './RedirectToLatestWorkspace';
|
||||
import RouteError from './RouteError';
|
||||
@@ -54,12 +50,6 @@ const router = createBrowserRouter([
|
||||
]);
|
||||
|
||||
export function AppRouter() {
|
||||
// Add some global hooks that should remain persistent
|
||||
useSyncModelStores();
|
||||
useSyncZoomSetting();
|
||||
useSyncFontSizeSetting();
|
||||
useGenerateThemeCss();
|
||||
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { emit } from '@tauri-apps/api/event';
|
||||
import type { PromptTextRequest, PromptTextResponse } from '@yaakapp-internal/plugin';
|
||||
import { useEnsureActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
||||
import {useGenerateThemeCss} from "../hooks/useGenerateThemeCss";
|
||||
import { useHotKey } from '../hooks/useHotKey';
|
||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||
import { useNotificationToast } from '../hooks/useNotificationToast';
|
||||
@@ -10,10 +11,18 @@ import { useRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||
import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||
import {useSyncFontSizeSetting} from "../hooks/useSyncFontSizeSetting";
|
||||
import {useSyncModelStores} from "../hooks/useSyncModelStores";
|
||||
import { useSyncWorkspaceChildModels } from '../hooks/useSyncWorkspaceChildModels';
|
||||
import {useSyncZoomSetting} from "../hooks/useSyncZoomSetting";
|
||||
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
|
||||
|
||||
export function GlobalHooks() {
|
||||
useSyncModelStores();
|
||||
useSyncZoomSetting();
|
||||
useSyncFontSizeSetting();
|
||||
useGenerateThemeCss();
|
||||
|
||||
// Include here so they always update, even if no component references them
|
||||
useRecentWorkspaces();
|
||||
useRecentEnvironments();
|
||||
|
||||
@@ -702,11 +702,11 @@ function SidebarItem({
|
||||
useScrollIntoView(ref.current, isActive);
|
||||
|
||||
const handleSubmitNameEdit = useCallback(
|
||||
(el: HTMLInputElement) => {
|
||||
async (el: HTMLInputElement) => {
|
||||
if (itemModel === 'http_request') {
|
||||
updateHttpRequest.mutate({ id: itemId, update: (r) => ({ ...r, name: el.value }) });
|
||||
await updateHttpRequest.mutateAsync({ id: itemId, update: (r) => ({ ...r, name: el.value }) });
|
||||
} else if (itemModel === 'grpc_request') {
|
||||
updateGrpcRequest.mutate({ id: itemId, update: (r) => ({ ...r, name: el.value }) });
|
||||
await updateGrpcRequest.mutateAsync({ id: itemId, update: (r) => ({ ...r, name: el.value }) });
|
||||
}
|
||||
setEditing(false);
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Folder, HttpRequest } from '@yaakapp-internal/models';
|
||||
import type {
|
||||
TemplateFunction,
|
||||
TemplateFunctionArg,
|
||||
@@ -12,6 +13,7 @@ import classNames from 'classnames';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useDebouncedValue } from '../hooks/useDebouncedValue';
|
||||
import { useFolders } from '../hooks/useFolders';
|
||||
import { useHttpRequests } from '../hooks/useHttpRequests';
|
||||
import { useRenderTemplate } from '../hooks/useRenderTemplate';
|
||||
import { useTemplateTokensToString } from '../hooks/useTemplateTokensToString';
|
||||
@@ -253,6 +255,7 @@ function HttpRequestArg({
|
||||
value: string;
|
||||
onChange: (v: string) => void;
|
||||
}) {
|
||||
const folders = useFolders();
|
||||
const httpRequests = useHttpRequests();
|
||||
const activeRequest = useActiveRequest();
|
||||
return (
|
||||
@@ -262,15 +265,35 @@ function HttpRequestArg({
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
options={[
|
||||
...httpRequests.map((r) => ({
|
||||
label: fallbackRequestName(r) + (activeRequest?.id === r.id ? ' (current)' : ''),
|
||||
value: r.id,
|
||||
})),
|
||||
...httpRequests.map((r) => {
|
||||
return {
|
||||
label: buildRequestBreadcrumbs(r, folders).join(' / ') + (r.id == activeRequest?.id ? ' (current)' : ''),
|
||||
value: r.id,
|
||||
};
|
||||
}),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function buildRequestBreadcrumbs(request: HttpRequest, folders: Folder[]): string[] {
|
||||
const ancestors: (HttpRequest | Folder)[] = [request];
|
||||
|
||||
const next = () => {
|
||||
const latest = ancestors[0];
|
||||
if (latest == null) return [];
|
||||
|
||||
const parent = folders.find((f) => f.id === latest.folderId);
|
||||
if (parent == null) return;
|
||||
|
||||
ancestors.unshift(parent);
|
||||
next();
|
||||
};
|
||||
next();
|
||||
|
||||
return ancestors.map((a) => (a.model === 'folder' ? a.name : fallbackRequestName(a)));
|
||||
}
|
||||
|
||||
function CheckboxArg({
|
||||
arg,
|
||||
onChange,
|
||||
|
||||
@@ -2,6 +2,7 @@ import classNames from 'classnames';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
||||
import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace';
|
||||
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
||||
import { usePrompt } from '../hooks/usePrompt';
|
||||
@@ -36,6 +37,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
const settings = useSettings();
|
||||
const openWorkspace = useOpenWorkspace();
|
||||
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
||||
const deleteSendHistory = useDeleteSendHistory();
|
||||
|
||||
const { workspaceItems, extraItems } = useMemo<{
|
||||
workspaceItems: RadioDropdownItem[];
|
||||
@@ -70,9 +72,15 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
updateWorkspace.mutate({ name });
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'delete-responses',
|
||||
label: 'Clear Send History',
|
||||
leftSlot: <Icon icon="history" />,
|
||||
onSelect: deleteSendHistory.mutate,
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: 'Delete',
|
||||
label: 'Delete Workspace',
|
||||
leftSlot: <Icon icon="trash" />,
|
||||
onSelect: deleteWorkspace.mutate,
|
||||
variant: 'danger',
|
||||
@@ -90,7 +98,8 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
||||
}, [
|
||||
activeWorkspace?.name,
|
||||
activeWorkspaceId,
|
||||
createWorkspace,
|
||||
createWorkspace.mutate,
|
||||
deleteSendHistory.mutate,
|
||||
deleteWorkspace.mutate,
|
||||
prompt,
|
||||
updateWorkspace,
|
||||
|
||||
@@ -350,8 +350,9 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
container: CSSProperties;
|
||||
menu: CSSProperties;
|
||||
triangle: CSSProperties;
|
||||
upsideDown: boolean;
|
||||
}>(() => {
|
||||
if (triggerShape == null) return { container: {}, triangle: {}, menu: {} };
|
||||
if (triggerShape == null) return { container: {}, triangle: {}, menu: {}, upsideDown: false };
|
||||
|
||||
const menuMarginY = 5;
|
||||
const docRect = document.documentElement.getBoundingClientRect();
|
||||
@@ -364,6 +365,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
const upsideDown = heightBelow < heightAbove && heightBelow < items.length * 25 + 20 + 200;
|
||||
const triggerWidth = triggerShape.right - triggerShape.left;
|
||||
return {
|
||||
upsideDown,
|
||||
container: {
|
||||
top: !upsideDown ? top + menuMarginY : undefined,
|
||||
bottom: upsideDown
|
||||
@@ -426,7 +428,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
<motion.div
|
||||
tabIndex={0}
|
||||
onKeyDown={handleMenuKeyDown}
|
||||
initial={{ opacity: 0, y: -5, scale: 0.98 }}
|
||||
initial={{ opacity: 0, y: (styles.upsideDown ? 1 : -1) * 5, scale: 0.98 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
|
||||
@@ -8,12 +8,12 @@ import classNames from 'classnames';
|
||||
import { EditorView } from 'codemirror';
|
||||
import type { MutableRefObject, ReactNode } from 'react';
|
||||
import {
|
||||
useEffect,
|
||||
Children,
|
||||
cloneElement,
|
||||
forwardRef,
|
||||
isValidElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useRef,
|
||||
@@ -343,6 +343,33 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
[forceUpdateKey],
|
||||
);
|
||||
|
||||
// For read-only mode, update content when `defaultValue` changes
|
||||
useEffect(() => {
|
||||
if (!readOnly || cm.current?.view == null || defaultValue == null) return;
|
||||
|
||||
// Replace codemirror contents
|
||||
const currentDoc = cm.current.view.state.doc.toString();
|
||||
if (defaultValue.startsWith(currentDoc)) {
|
||||
// If we're just appending, append only the changes. This preserves
|
||||
// things like scroll position.
|
||||
cm.current.view.dispatch({
|
||||
changes: cm.current.view.state.changes({
|
||||
from: currentDoc.length,
|
||||
insert: defaultValue.slice(currentDoc.length),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
// If we're replacing everything, reset the entire content
|
||||
cm.current.view.dispatch({
|
||||
changes: cm.current.view.state.changes({
|
||||
from: 0,
|
||||
to: currentDoc.length,
|
||||
insert: defaultValue,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}, [defaultValue, readOnly]);
|
||||
|
||||
// Add bg classes to actions, so they appear over the text
|
||||
const decoratedActions = useMemo(() => {
|
||||
const results = [];
|
||||
|
||||
@@ -26,7 +26,7 @@ const icons = {
|
||||
chevron_down: lucide.ChevronDownIcon,
|
||||
chevron_right: lucide.ChevronRightIcon,
|
||||
circle_alert: lucide.CircleAlertIcon,
|
||||
cloud: lucide.CloudIcon,
|
||||
clock: lucide.ClockIcon,
|
||||
code: lucide.CodeIcon,
|
||||
cookie: lucide.CookieIcon,
|
||||
copy: lucide.CopyIcon,
|
||||
@@ -48,6 +48,7 @@ const icons = {
|
||||
grip_vertical: lucide.GripVerticalIcon,
|
||||
hand: lucide.HandIcon,
|
||||
help: lucide.CircleHelpIcon,
|
||||
history: lucide.HistoryIcon,
|
||||
house: lucide.HomeIcon,
|
||||
info: lucide.InfoIcon,
|
||||
keyboard: lucide.KeyboardIcon,
|
||||
|
||||
@@ -128,6 +128,9 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
|
||||
type={type === 'password' && !obscured ? 'text' : type}
|
||||
defaultValue={defaultValue}
|
||||
placeholder={placeholder}
|
||||
autoComplete="off"
|
||||
autoCapitalize="off"
|
||||
autoCorrect="off"
|
||||
onChange={(e) => handleChange(e.target.value)}
|
||||
onPaste={(e) => onPaste?.(e.clipboardData.getData('Text'))}
|
||||
className={inputClassName}
|
||||
|
||||
@@ -65,7 +65,14 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
<Separator />
|
||||
</div>
|
||||
<div className="pl-2 overflow-y-auto">
|
||||
<div className="mb-2 select-text cursor-text font-semibold">Message Received</div>
|
||||
<HStack space={1.5} className="mb-2 select-text cursor-text font-semibold">
|
||||
<EventLabels
|
||||
className="text-sm"
|
||||
event={activeEvent}
|
||||
index={activeEventIndex ?? 0}
|
||||
/>
|
||||
Message Received
|
||||
</HStack>
|
||||
{!showLarge && activeEvent.data.length > 1000 * 1000 ? (
|
||||
<VStack space={2} className="italic text-text-subtlest">
|
||||
Message previews larger than 1MB are hidden
|
||||
@@ -90,7 +97,6 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
) : (
|
||||
<Editor
|
||||
readOnly
|
||||
forceUpdateKey={activeEvent.id ?? activeEvent.data}
|
||||
defaultValue={tryFormatJson(activeEvent.data)}
|
||||
language={language}
|
||||
/>
|
||||
@@ -149,6 +155,7 @@ function EventStreamEventsVirtual({
|
||||
<EventStreamEvent
|
||||
event={event}
|
||||
isActive={virtualItem.index === activeEventIndex}
|
||||
index={virtualItem.index}
|
||||
onClick={() => {
|
||||
if (virtualItem.index === activeEventIndex) setActiveEventIndex(null);
|
||||
else setActiveEventIndex(virtualItem.index);
|
||||
@@ -167,11 +174,13 @@ function EventStreamEvent({
|
||||
isActive,
|
||||
event,
|
||||
className,
|
||||
index,
|
||||
}: {
|
||||
onClick: () => void;
|
||||
isActive: boolean;
|
||||
event: ServerSentEvent;
|
||||
className?: string;
|
||||
index: number;
|
||||
}) {
|
||||
return (
|
||||
<motion.button
|
||||
@@ -187,19 +196,33 @@ function EventStreamEvent({
|
||||
)}
|
||||
>
|
||||
<Icon className={classNames('text-info')} title="Server Message" icon="arrow_big_down_dash" />
|
||||
<HStack space={1.5} className="text-sm">
|
||||
{event.eventType && (
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
{event.eventType}
|
||||
</InlineCode>
|
||||
)}
|
||||
{event.id && (
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
{event.id}
|
||||
</InlineCode>
|
||||
)}
|
||||
</HStack>
|
||||
<EventLabels className="text-sm" event={event} isActive={isActive} index={index} />
|
||||
<div className={classNames('w-full truncate text-xs')}>{event.data.slice(0, 1000)}</div>
|
||||
</motion.button>
|
||||
);
|
||||
}
|
||||
|
||||
function EventLabels({
|
||||
className,
|
||||
event,
|
||||
index,
|
||||
isActive,
|
||||
}: {
|
||||
event: ServerSentEvent;
|
||||
index: number;
|
||||
className: string;
|
||||
isActive?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<HStack space={1.5} alignItems="center" className={className}>
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
{event.id ?? index}
|
||||
</InlineCode>
|
||||
{event.eventType && (
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
{event.eventType}
|
||||
</InlineCode>
|
||||
)}
|
||||
</HStack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
className={textViewerClassName}
|
||||
onSaveResponse={saveResponse.mutate}
|
||||
responseId={response.id}
|
||||
requestId={response.requestId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ interface Props {
|
||||
text: string;
|
||||
language: EditorProps['language'];
|
||||
responseId: string;
|
||||
requestId: string;
|
||||
onSaveResponse: () => void;
|
||||
}
|
||||
|
||||
@@ -37,20 +38,21 @@ export function TextViewer({
|
||||
language,
|
||||
text,
|
||||
responseId,
|
||||
requestId,
|
||||
pretty,
|
||||
className,
|
||||
onSaveResponse,
|
||||
}: Props) {
|
||||
const [filterTextMap, setFilterTextMap] = useFilterText();
|
||||
const [showLargeResponse, toggleShowLargeResponse] = useToggle();
|
||||
const filterText = filterTextMap[responseId] ?? null;
|
||||
const filterText = filterTextMap[requestId] ?? null;
|
||||
const copy = useCopy();
|
||||
const debouncedFilterText = useDebouncedValue(filterText, 200);
|
||||
const setFilterText = useCallback(
|
||||
(v: string | null) => {
|
||||
setFilterTextMap((m) => ({ ...m, [responseId]: v }));
|
||||
setFilterTextMap((m) => ({ ...m, [requestId]: v }));
|
||||
},
|
||||
[setFilterTextMap, responseId],
|
||||
[setFilterTextMap, requestId],
|
||||
);
|
||||
|
||||
const isSearching = filterText != null;
|
||||
@@ -75,7 +77,7 @@ export function TextViewer({
|
||||
nodes.push(
|
||||
<div key="input" className="w-full !opacity-100">
|
||||
<Input
|
||||
key={responseId}
|
||||
key={requestId}
|
||||
validate={!filteredResponse.error}
|
||||
hideLabel
|
||||
autoFocus
|
||||
@@ -110,7 +112,7 @@ export function TextViewer({
|
||||
filteredResponse.error,
|
||||
isSearching,
|
||||
language,
|
||||
responseId,
|
||||
requestId,
|
||||
setFilterText,
|
||||
toggleSearch,
|
||||
]);
|
||||
@@ -160,7 +162,6 @@ export function TextViewer({
|
||||
<Editor
|
||||
readOnly
|
||||
className={className}
|
||||
forceUpdateKey={body}
|
||||
defaultValue={body}
|
||||
language={language}
|
||||
actions={actions}
|
||||
|
||||
@@ -4,20 +4,17 @@ import { useDialog } from '../components/DialogContext';
|
||||
import type { AlertProps } from './Alert';
|
||||
import { Alert } from './Alert';
|
||||
|
||||
interface AlertArg {
|
||||
id: string;
|
||||
title: DialogProps['title'];
|
||||
body: AlertProps['body'];
|
||||
size?: DialogProps['size'];
|
||||
}
|
||||
|
||||
export function useAlert() {
|
||||
const dialog = useDialog();
|
||||
return useCallback(
|
||||
({
|
||||
id,
|
||||
title,
|
||||
body,
|
||||
size = 'sm',
|
||||
}: {
|
||||
id: string;
|
||||
title: DialogProps['title'];
|
||||
body: AlertProps['body'];
|
||||
size?: DialogProps['size'];
|
||||
}) =>
|
||||
return useCallback<(a: AlertArg) => void>(
|
||||
({ id, title, body, size = 'sm' }: AlertArg) =>
|
||||
dialog.show({
|
||||
id,
|
||||
title,
|
||||
|
||||
43
src-web/hooks/useDeleteSendHistory.tsx
Normal file
43
src-web/hooks/useDeleteSendHistory.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspace } from './useActiveWorkspace';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { useGrpcConnections } from './useGrpcConnections';
|
||||
import { useHttpResponses } from './useHttpResponses';
|
||||
|
||||
export function useDeleteSendHistory() {
|
||||
const confirm = useConfirm();
|
||||
const alert = useAlert();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const httpResponses = useHttpResponses();
|
||||
const grpcConnections = useGrpcConnections();
|
||||
const labels = [
|
||||
httpResponses.length > 0 ? count('Http Response', httpResponses.length) : null,
|
||||
grpcConnections.length > 0 ? count('Grpc Connection', grpcConnections.length) : null,
|
||||
].filter((l) => l != null);
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ['delete_send_history'],
|
||||
mutationFn: async () => {
|
||||
if (labels.length === 0) {
|
||||
alert({
|
||||
id: 'no-responses',
|
||||
title: 'Nothing to Delete',
|
||||
body: 'There are no Http Response or Grpc Connections to delete',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await confirm({
|
||||
id: 'delete-send-history',
|
||||
title: 'Clear Send History',
|
||||
variant: 'delete',
|
||||
description: <>Delete {labels.join(' and ')}?</>,
|
||||
});
|
||||
if (!confirmed) return;
|
||||
await invokeCmd('cmd_delete_send_history', { workspaceId: activeWorkspace?.id ?? 'n/a' });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { emit } from '@tauri-apps/api/event';
|
||||
import type { GrpcConnection, GrpcRequest } from '@yaakapp-internal/models';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import { isResponseLoading } from '../lib/model_util';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
@@ -22,27 +23,27 @@ export function useGrpc(
|
||||
|
||||
const go = useMutation<void, string>({
|
||||
mutationKey: ['grpc_go', conn?.id],
|
||||
mutationFn: async () =>
|
||||
await invokeCmd('cmd_grpc_go', { requestId, environmentId: environment?.id, protoFiles }),
|
||||
mutationFn: () =>
|
||||
invokeCmd<void>('cmd_grpc_go', { requestId, environmentId: environment?.id, protoFiles }),
|
||||
onSettled: () => trackEvent('grpc_request', 'send'),
|
||||
});
|
||||
|
||||
const send = useMutation({
|
||||
mutationKey: ['grpc_send', conn?.id],
|
||||
mutationFn: async ({ message }: { message: string }) =>
|
||||
await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, { Message: message }),
|
||||
mutationFn: ({ message }: { message: string }) =>
|
||||
emit(`grpc_client_msg_${conn?.id ?? 'none'}`, { Message: message }),
|
||||
onSettled: () => trackEvent('grpc_connection', 'send'),
|
||||
});
|
||||
|
||||
const cancel = useMutation({
|
||||
mutationKey: ['grpc_cancel', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Cancel'),
|
||||
mutationFn: () => emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Cancel'),
|
||||
onSettled: () => trackEvent('grpc_connection', 'cancel'),
|
||||
});
|
||||
|
||||
const commit = useMutation({
|
||||
mutationKey: ['grpc_commit', conn?.id ?? 'n/a'],
|
||||
mutationFn: async () => await emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Commit'),
|
||||
mutationFn: () => emit(`grpc_client_msg_${conn?.id ?? 'none'}`, 'Commit'),
|
||||
onSettled: () => trackEvent('grpc_connection', 'commit'),
|
||||
});
|
||||
|
||||
@@ -51,11 +52,11 @@ export function useGrpc(
|
||||
const reflect = useQuery<ReflectResponseService[], string>({
|
||||
enabled: req != null,
|
||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, protoFiles],
|
||||
queryFn: async () =>
|
||||
(await minPromiseMillis(
|
||||
queryFn: () =>
|
||||
minPromiseMillis<ReflectResponseService[]>(
|
||||
invokeCmd('cmd_grpc_reflect', { requestId, protoFiles }),
|
||||
300,
|
||||
)) as ReflectResponseService[],
|
||||
),
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -63,7 +64,7 @@ export function useGrpc(
|
||||
reflect,
|
||||
cancel,
|
||||
commit,
|
||||
isStreaming: conn != null && conn.elapsed === 0,
|
||||
isStreaming: isResponseLoading(conn),
|
||||
send,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AnyModel } from '@yaakapp-internal/models';
|
||||
import { useSetAtom } from 'jotai/index';
|
||||
import { extractKeyValue } from '../lib/keyValueStore';
|
||||
import { modelsEq } from '../lib/model_util';
|
||||
import {useActiveWorkspace} from "./useActiveWorkspace";
|
||||
import { cookieJarsAtom } from './useCookieJars';
|
||||
import { environmentsAtom } from './useEnvironments';
|
||||
import { foldersAtom } from './useFolders';
|
||||
@@ -25,6 +26,7 @@ export interface ModelPayload {
|
||||
}
|
||||
|
||||
export function useSyncModelStores() {
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const queryClient = useQueryClient();
|
||||
const { wasUpdatedExternally } = useRequestUpdateKey(null);
|
||||
|
||||
@@ -48,10 +50,17 @@ export function useSyncModelStores() {
|
||||
? keyValueQueryKey(model)
|
||||
: null;
|
||||
|
||||
// TODO: Move this logic to useRequestEditor() hook
|
||||
if (model.model === 'http_request' && windowLabel !== getCurrentWebviewWindow().label) {
|
||||
wasUpdatedExternally(model.id);
|
||||
}
|
||||
|
||||
// Only sync models that belong to this workspace, if a workspace ID is present
|
||||
if ('workspaceId' in model && model.workspaceId !== activeWorkspace?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark these models as DESC instead of ASC
|
||||
const pushToFront = (['http_response', 'grpc_connection'] as AnyModel['model'][]).includes(
|
||||
model.model,
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ type TauriCmd =
|
||||
| 'cmd_curl_to_request'
|
||||
| 'cmd_delete_all_grpc_connections'
|
||||
| 'cmd_delete_all_http_responses'
|
||||
| 'cmd_delete_send_history'
|
||||
| 'cmd_delete_cookie_jar'
|
||||
| 'cmd_delete_environment'
|
||||
| 'cmd_delete_folder'
|
||||
|
||||
Reference in New Issue
Block a user