mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-02-16 15:47:47 +01:00
Compare commits
15 Commits
v2024.6.5
...
v2024.7.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b8a18edae | ||
|
|
0bb3f14b4c | ||
|
|
c18d30b89f | ||
|
|
8f06a834c8 | ||
|
|
bd948f9cd6 | ||
|
|
d70254bcdc | ||
|
|
fac5385d5d | ||
|
|
e8bcc695bb | ||
|
|
88aeb0e530 | ||
|
|
92b1582232 | ||
|
|
196990c077 | ||
|
|
c42b8cf538 | ||
|
|
085274c960 | ||
|
|
7ef187abf6 | ||
|
|
12eac34d95 |
@@ -12,7 +12,7 @@ module.exports = {
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"]
|
||||
},
|
||||
ignorePatterns: ["src-tauri/**/*", "plugins/**/*"],
|
||||
ignorePatterns: ["scripts/**/*", "src-tauri/**/*", "plugins/**/*"],
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect"
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -54,6 +54,10 @@ jobs:
|
||||
run: npm run lint
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
- name: Set version
|
||||
run: npm run replace-version
|
||||
env:
|
||||
YAAK_VERSION: ${{ github.ref_name }}
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
34
package-lock.json
generated
34
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "yaak-app",
|
||||
"name": "yaak",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "yaak-app",
|
||||
"name": "yaak",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.2.1",
|
||||
@@ -497,9 +497,9 @@
|
||||
"integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg=="
|
||||
},
|
||||
"node_modules/@codemirror/autocomplete": {
|
||||
"version": "6.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.0.tgz",
|
||||
"integrity": "sha512-P/LeCTtZHRTCU4xQsa89vSKWecYv1ZqwzOd5topheGRf+qtacFgBeIMQi3eL8Kt/BUNvxUWkx+5qP2jlGoARrg==",
|
||||
"version": "6.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.3.tgz",
|
||||
"integrity": "sha512-Vl/tIeRVVUCRDuOG48lttBasNQu8usGgXQawBXI7WJAiUDSFOfzflmEsZFZo48mAvAaa4FZ/4/yLLxFtdJaKYA==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
@@ -561,9 +561,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/language": {
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz",
|
||||
"integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
|
||||
"version": "6.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz",
|
||||
"integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.23.0",
|
||||
@@ -574,9 +574,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lint": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.7.0.tgz",
|
||||
"integrity": "sha512-LTLOL2nT41ADNSCCCCw8Q/UmdAFzB23OUYSjsHTdsVaH0XEo+orhuqbDNWzrzodm14w6FOxqxpmy4LF8Lixqjw==",
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz",
|
||||
"integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0",
|
||||
@@ -599,9 +599,9 @@
|
||||
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.26.3",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz",
|
||||
"integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==",
|
||||
"version": "6.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.1.tgz",
|
||||
"integrity": "sha512-BUWr+zCJpMkA/u69HlJmR+YkV4yPpM81HeMkOMZuwFa8iM5uJdEPKAs1icIRZKkKmy0Ub1x9/G3PQLTXdpBxrQ==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"style-mod": "^4.1.0",
|
||||
@@ -7369,9 +7369,9 @@
|
||||
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
|
||||
},
|
||||
"node_modules/json-schema-library": {
|
||||
"version": "9.3.4",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-9.3.4.tgz",
|
||||
"integrity": "sha512-220lm9RVt9BUeF2QhBT711aX4IogUHhPT8Tjhkksc4CUw8WmChFMuf0mJdpDAHDfJDkI064jcZIH8P70HdPAOA==",
|
||||
"version": "9.3.5",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-9.3.5.tgz",
|
||||
"integrity": "sha512-5eBDx7cbfs+RjylsVO+N36b0GOPtv78rfqgf2uON+uaHUIC62h63Y8pkV2ovKbaL4ZpQcHp21968x5nx/dFwqQ==",
|
||||
"dependencies": {
|
||||
"@sagold/json-pointer": "^5.1.2",
|
||||
"@sagold/json-query": "^6.1.3",
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
"build:plugin:filter-xpath": "cd plugins/filter-xpath && vite build --emptyOutDir",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage",
|
||||
"prepare": "husky install"
|
||||
"prepare": "husky install",
|
||||
"replace-version": "node ./scripts/replace-version.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.2.1",
|
||||
|
||||
15
scripts/replace-version.cjs
Normal file
15
scripts/replace-version.cjs
Normal file
@@ -0,0 +1,15 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const version = process.env.YAAK_VERSION?.replace('v', '');
|
||||
if (!version) {
|
||||
throw new Error('YAAK_VERSION environment variable not set')
|
||||
}
|
||||
|
||||
const tauriConfigPath = path.join(__dirname, '../src-tauri/tauri.conf.json');
|
||||
const tauriConfig = JSON.parse(fs.readFileSync(tauriConfigPath, 'utf8'));
|
||||
|
||||
tauriConfig.version = version;
|
||||
|
||||
console.log('Writing version ' + version + ' to ' + tauriConfigPath)
|
||||
fs.writeFileSync(tauriConfigPath, JSON.stringify(tauriConfig, null, 2));
|
||||
7
src-tauri/Cargo.lock
generated
7
src-tauri/Cargo.lock
generated
@@ -2290,6 +2290,7 @@ dependencies = [
|
||||
"hyper 0.14.29",
|
||||
"hyper-rustls 0.24.2",
|
||||
"log",
|
||||
"md5",
|
||||
"prost",
|
||||
"prost-reflect",
|
||||
"prost-types",
|
||||
@@ -3250,6 +3251,12 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
|
||||
@@ -20,3 +20,4 @@ hyper-rustls = { version = "0.24.0", features = ["http2"] }
|
||||
uuid = { version = "1.7.0", features = ["v4"] }
|
||||
tauri = { version = "2.0.0-beta" }
|
||||
tauri-plugin-shell = "2.0.0-beta"
|
||||
md5 = "0.7.0"
|
||||
|
||||
@@ -16,7 +16,9 @@ use tonic::transport::Uri;
|
||||
use tonic::{IntoRequest, IntoStreamingRequest, Request, Response, Status, Streaming};
|
||||
|
||||
use crate::codec::DynamicCodec;
|
||||
use crate::proto::{fill_pool, fill_pool_from_files, get_transport, method_desc_to_path};
|
||||
use crate::proto::{
|
||||
fill_pool_from_files, fill_pool_from_reflection, get_transport, method_desc_to_path,
|
||||
};
|
||||
use crate::{json_schema, MethodDefinition, ServiceDefinition};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -182,30 +184,37 @@ impl GrpcHandle {
|
||||
}
|
||||
|
||||
impl GrpcHandle {
|
||||
pub async fn services_from_files(
|
||||
pub async fn reflect(
|
||||
&mut self,
|
||||
id: &str,
|
||||
uri: &str,
|
||||
paths: Vec<PathBuf>,
|
||||
) -> Result<Vec<ServiceDefinition>, String> {
|
||||
let pool = fill_pool_from_files(&self.app_handle, paths).await?;
|
||||
let uri = Uri::from_str(uri).map_err(|e| e.to_string())?;
|
||||
self.pools.insert(self.get_pool_key(id, &uri), pool.clone());
|
||||
Ok(self.services_from_pool(&pool))
|
||||
}
|
||||
pub async fn services_from_reflection(
|
||||
&mut self,
|
||||
id: &str,
|
||||
uri: &str,
|
||||
) -> Result<Vec<ServiceDefinition>, String> {
|
||||
let uri = Uri::from_str(uri).map_err(|e| e.to_string())?;
|
||||
let pool = fill_pool(&uri).await?;
|
||||
self.pools.insert(self.get_pool_key(id, &uri), pool.clone());
|
||||
Ok(self.services_from_pool(&pool))
|
||||
proto_files: &Vec<PathBuf>,
|
||||
) -> Result<(), String> {
|
||||
let pool = if proto_files.is_empty() {
|
||||
let full_uri = uri_from_str(uri)?;
|
||||
fill_pool_from_reflection(&full_uri).await
|
||||
} else {
|
||||
fill_pool_from_files(&self.app_handle, proto_files).await
|
||||
}?;
|
||||
|
||||
self.pools
|
||||
.insert(make_pool_key(id, uri, proto_files), pool.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_pool_key(&self, id: &str, uri: &Uri) -> String {
|
||||
format!("{}-{}", id, uri)
|
||||
pub async fn services(
|
||||
&mut self,
|
||||
id: &str,
|
||||
uri: &str,
|
||||
proto_files: &Vec<PathBuf>,
|
||||
) -> Result<Vec<ServiceDefinition>, String> {
|
||||
// Ensure reflection is up-to-date
|
||||
self.reflect(id, uri, proto_files).await?;
|
||||
|
||||
let pool = self
|
||||
.get_pool(id, uri, proto_files)
|
||||
.ok_or("Failed to get pool".to_string())?;
|
||||
Ok(self.services_from_pool(&pool))
|
||||
}
|
||||
|
||||
fn services_from_pool(&self, pool: &DescriptorPool) -> Vec<ServiceDefinition> {
|
||||
@@ -237,25 +246,26 @@ impl GrpcHandle {
|
||||
&mut self,
|
||||
id: &str,
|
||||
uri: &str,
|
||||
proto_files: Vec<PathBuf>,
|
||||
proto_files: &Vec<PathBuf>,
|
||||
) -> Result<GrpcConnection, String> {
|
||||
let uri = Uri::from_str(uri).map_err(|e| e.to_string())?;
|
||||
let pool = match self.pools.get(id) {
|
||||
Some(p) => p.clone(),
|
||||
None => match proto_files.len() {
|
||||
0 => fill_pool(&uri).await?,
|
||||
_ => {
|
||||
let pool = fill_pool_from_files(&self.app_handle, proto_files).await?;
|
||||
self.pools.insert(id.to_string(), pool.clone());
|
||||
pool
|
||||
}
|
||||
},
|
||||
};
|
||||
self.reflect(id, uri, proto_files).await?;
|
||||
let pool = self
|
||||
.get_pool(id, uri, proto_files)
|
||||
.ok_or("Failed to get pool")?;
|
||||
|
||||
let uri = uri_from_str(uri)?;
|
||||
let conn = get_transport();
|
||||
let connection = GrpcConnection { pool, conn, uri };
|
||||
let connection = GrpcConnection {
|
||||
pool: pool.clone(),
|
||||
conn,
|
||||
uri,
|
||||
};
|
||||
Ok(connection)
|
||||
}
|
||||
|
||||
fn get_pool(&self, id: &str, uri: &str, proto_files: &Vec<PathBuf>) -> Option<&DescriptorPool> {
|
||||
self.pools.get(make_pool_key(id, uri, proto_files).as_str())
|
||||
}
|
||||
}
|
||||
|
||||
fn decorate_req<T>(metadata: HashMap<String, String>, req: &mut Request<T>) -> Result<(), String> {
|
||||
@@ -267,3 +277,28 @@ fn decorate_req<T>(metadata: HashMap<String, String>, req: &mut Request<T>) -> R
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn uri_from_str(uri_str: &str) -> Result<Uri, String> {
|
||||
match Uri::from_str(uri_str) {
|
||||
Ok(uri) => Ok(uri),
|
||||
Err(err) => {
|
||||
// Uri::from_str basically only returns "invalid format" so we add more context here
|
||||
Err(format!("Failed to parse URL, {}", err.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_pool_key(id: &str, uri: &str, proto_files: &Vec<PathBuf>) -> String {
|
||||
let pool_key = format!(
|
||||
"{}::{}::{}",
|
||||
id,
|
||||
uri,
|
||||
proto_files
|
||||
.iter()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(":")
|
||||
);
|
||||
|
||||
format!("{:x}", md5::compute(pool_key))
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use tonic_reflection::pb::ServerReflectionRequest;
|
||||
|
||||
pub async fn fill_pool_from_files(
|
||||
app_handle: &AppHandle,
|
||||
paths: Vec<PathBuf>,
|
||||
paths: &Vec<PathBuf>,
|
||||
) -> Result<DescriptorPool, String> {
|
||||
let mut pool = DescriptorPool::new();
|
||||
let random_file_name = format!("{}.desc", uuid::Uuid::new_v4());
|
||||
@@ -121,7 +121,7 @@ pub async fn fill_pool_from_files(
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
pub async fn fill_pool(uri: &Uri) -> Result<DescriptorPool, String> {
|
||||
pub async fn fill_pool_from_reflection(uri: &Uri) -> Result<DescriptorPool, String> {
|
||||
let mut pool = DescriptorPool::new();
|
||||
let mut client = ServerReflectionClient::with_origin(get_transport(), uri.clone());
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ extern crate objc;
|
||||
use std::collections::HashMap;
|
||||
use std::env::current_dir;
|
||||
use std::fs;
|
||||
use std::fs::{create_dir_all, File, read_to_string};
|
||||
use std::fs::{create_dir_all, read_to_string, File};
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use std::str::FromStr;
|
||||
@@ -17,45 +17,45 @@ use fern::colors::ColoredLevelConfig;
|
||||
use log::{debug, error, info, warn};
|
||||
use rand::random;
|
||||
use serde_json::{json, Value};
|
||||
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::SqliteConnectOptions;
|
||||
use sqlx::types::Json;
|
||||
use tauri::{AppHandle, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
|
||||
use tauri::{Manager, WindowEvent};
|
||||
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||
use tauri::path::BaseDirectory;
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri::TitleBarStyle;
|
||||
use tauri::{AppHandle, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
|
||||
use tauri::{Manager, WindowEvent};
|
||||
use tauri_plugin_log::{fern, Target, TargetKind};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use ::grpc::{Code, deserialize_message, serialize_message, ServiceDefinition};
|
||||
use ::grpc::manager::{DynamicMessage, GrpcHandle};
|
||||
use ::grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||
|
||||
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||
use crate::grpc::metadata_to_map;
|
||||
use crate::http_request::send_http_request;
|
||||
use crate::models::{
|
||||
cancel_pending_grpc_connections, cancel_pending_responses, CookieJar,
|
||||
create_http_response, delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar,
|
||||
delete_environment, delete_folder, delete_grpc_connection, delete_grpc_request,
|
||||
delete_http_request, delete_http_response, delete_workspace, duplicate_grpc_request,
|
||||
duplicate_http_request, Environment, EnvironmentVariable, Folder, generate_model_id,
|
||||
get_cookie_jar, get_environment, get_folder, get_grpc_connection,
|
||||
cancel_pending_grpc_connections, cancel_pending_responses, create_http_response,
|
||||
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
||||
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
|
||||
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
|
||||
generate_model_id, get_cookie_jar, get_environment, get_folder, get_grpc_connection,
|
||||
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
||||
get_or_create_settings, get_workspace, get_workspace_export_resources, GrpcConnection, GrpcEvent,
|
||||
GrpcEventType, GrpcRequest, HttpRequest, HttpResponse, KeyValue,
|
||||
list_cookie_jars, list_environments, list_folders, list_grpc_connections, list_grpc_events,
|
||||
list_grpc_requests, list_http_requests, list_responses, list_workspaces, ModelType,
|
||||
set_key_value_raw, Settings, update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment,
|
||||
upsert_folder, upsert_grpc_connection, upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace, Workspace,
|
||||
get_or_create_settings, get_workspace, get_workspace_export_resources, list_cookie_jars,
|
||||
list_environments, list_folders, list_grpc_connections, list_grpc_events, list_grpc_requests,
|
||||
list_http_requests, list_responses, list_workspaces, set_key_value_raw, update_response_if_id,
|
||||
update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
||||
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace, CookieJar,
|
||||
Environment, EnvironmentVariable, Folder, GrpcConnection, GrpcEvent, GrpcEventType,
|
||||
GrpcRequest, HttpRequest, HttpResponse, KeyValue, ModelType, Settings, Workspace,
|
||||
WorkspaceExportResources,
|
||||
};
|
||||
use crate::notifications::YaakNotifier;
|
||||
use crate::plugin::{
|
||||
find_plugins, get_plugin, ImportResult, PluginCapability,
|
||||
run_plugin_export_curl, run_plugin_filter, run_plugin_import,
|
||||
find_plugins, get_plugin, run_plugin_export_curl, run_plugin_filter, run_plugin_import,
|
||||
ImportResult, PluginCapability,
|
||||
};
|
||||
use crate::render::{render_request, variables_from_environment};
|
||||
use crate::updates::{UpdateMode, YaakUpdater};
|
||||
@@ -134,27 +134,21 @@ async fn cmd_grpc_reflect(
|
||||
let req = get_grpc_request(&window, request_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let uri = safe_uri(req.url.as_str());
|
||||
if proto_files.len() > 0 {
|
||||
grpc_handle
|
||||
.lock()
|
||||
.await
|
||||
.services_from_files(
|
||||
&req.id,
|
||||
uri.as_str(),
|
||||
proto_files
|
||||
.iter()
|
||||
.map(|p| PathBuf::from_str(p).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
grpc_handle
|
||||
.lock()
|
||||
.await
|
||||
.services_from_reflection(&req.id, uri.as_str())
|
||||
.await
|
||||
}
|
||||
|
||||
let uri = safe_uri(&req.url);
|
||||
|
||||
grpc_handle
|
||||
.lock()
|
||||
.await
|
||||
.services(
|
||||
&req.id,
|
||||
&uri,
|
||||
&proto_files
|
||||
.iter()
|
||||
.map(|p| PathBuf::from_str(p).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -231,6 +225,7 @@ async fn cmd_grpc_go(
|
||||
workspace_id: req.workspace_id,
|
||||
request_id: req.id,
|
||||
status: -1,
|
||||
elapsed: 0,
|
||||
url: req.url.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -238,6 +233,7 @@ async fn cmd_grpc_go(
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
};
|
||||
|
||||
let conn_id = conn.id.clone();
|
||||
|
||||
let base_msg = GrpcEvent {
|
||||
@@ -270,12 +266,29 @@ async fn cmd_grpc_go(
|
||||
.connect(
|
||||
&req.clone().id,
|
||||
uri.as_str(),
|
||||
proto_files
|
||||
&proto_files
|
||||
.iter()
|
||||
.map(|p| PathBuf::from_str(p).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let connection = match connection {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
upsert_grpc_connection(
|
||||
&w,
|
||||
&GrpcConnection {
|
||||
elapsed: start.elapsed().as_millis() as i64,
|
||||
error: Some(err.clone()),
|
||||
..conn.clone()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Ok(conn_id);
|
||||
}
|
||||
};
|
||||
|
||||
let method_desc = connection
|
||||
.method(&service, &method)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"productName": "yaak",
|
||||
"version": "2024.6.5",
|
||||
"version": "0.0.0",
|
||||
"identifier": "app.yaak.desktop",
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm run build",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||
import { MotionConfig } from 'framer-motion';
|
||||
import { Suspense } from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
@@ -19,12 +20,12 @@ const queryClient = new QueryClient({
|
||||
export function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ReactQueryDevtools initialIsOpen={false} />
|
||||
<MotionConfig transition={{ duration: 0.1 }}>
|
||||
<HelmetProvider>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Suspense>
|
||||
<AppRouter />
|
||||
{/*<ReactQueryDevtools initialIsOpen={false} />*/}
|
||||
</Suspense>
|
||||
</DndProvider>
|
||||
</HelmetProvider>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import classNames from 'classnames';
|
||||
import { search } from 'fast-fuzzy';
|
||||
import type { KeyboardEvent, ReactNode } from 'react';
|
||||
@@ -25,6 +24,7 @@ import { useRequests } from '../hooks/useRequests';
|
||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { CookieDialog } from './CookieDialog';
|
||||
import { Button } from './core/Button';
|
||||
import { Heading } from './core/Heading';
|
||||
@@ -82,7 +82,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
action: 'settings.show',
|
||||
onSelect: async () => {
|
||||
if (workspaceId == null) return;
|
||||
await invoke('cmd_new_nested_window', {
|
||||
await invokeCmd('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import slugify from 'slugify';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { Button } from './core/Button';
|
||||
import { Checkbox } from './core/Checkbox';
|
||||
import { HStack, VStack } from './core/Stacks';
|
||||
@@ -49,7 +49,7 @@ export function ExportDataDialog({
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('cmd_export_data', { workspaceIds: ids, exportPath });
|
||||
await invokeCmd('cmd_export_data', { workspaceIds: ids, exportPath });
|
||||
onHide();
|
||||
onSuccess(exportPath);
|
||||
}, [onHide, onSuccess, selectedWorkspaces, workspaces]);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { updateSchema } from 'cm6-graphql';
|
||||
import type { EditorView } from 'codemirror';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL';
|
||||
@@ -10,6 +9,7 @@ import { Editor, formatGraphQL } from './core/Editor';
|
||||
import { FormattedError } from './core/FormattedError';
|
||||
import { Separator } from './core/Separator';
|
||||
import { useDialog } from './DialogContext';
|
||||
import { updateSchema } from 'cm6-graphql';
|
||||
|
||||
type Props = Pick<
|
||||
EditorProps,
|
||||
@@ -43,7 +43,13 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi
|
||||
}, [defaultValue]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(b: GraphQLBody) => onChange?.(JSON.stringify(b, null, 2)),
|
||||
(b: GraphQLBody) => {
|
||||
try {
|
||||
onChange?.(JSON.stringify(b, null, 2));
|
||||
} catch (err) {
|
||||
// Meh, not much we can do here
|
||||
}
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
@@ -53,24 +59,65 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi
|
||||
);
|
||||
|
||||
const handleChangeVariables = useCallback(
|
||||
(variables: string) => {
|
||||
try {
|
||||
handleChange({ query, variables: JSON.parse(variables) });
|
||||
} catch (e) {
|
||||
// Meh, not much we can do here
|
||||
}
|
||||
},
|
||||
(variables: string) => handleChange({ query, variables: JSON.parse(variables) }),
|
||||
[handleChange, query],
|
||||
);
|
||||
|
||||
// Refetch the schema when the URL changes
|
||||
useEffect(() => {
|
||||
if (editorViewRef.current === null) return;
|
||||
updateSchema(editorViewRef.current, schema);
|
||||
updateSchema(editorViewRef.current, schema ?? undefined);
|
||||
}, [schema]);
|
||||
|
||||
const dialog = useDialog();
|
||||
|
||||
const actions = useMemo<EditorProps['actions']>(() => {
|
||||
const isValid = error || isLoading;
|
||||
if (!isValid) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const actions: EditorProps['actions'] = [
|
||||
<div key="introspection" className="!opacity-100">
|
||||
<Button
|
||||
key="introspection"
|
||||
size="xs"
|
||||
color={error ? 'danger' : 'secondary'}
|
||||
isLoading={isLoading}
|
||||
onClick={() => {
|
||||
dialog.show({
|
||||
title: 'Introspection Failed',
|
||||
size: 'dynamic',
|
||||
id: 'introspection-failed',
|
||||
render: () => (
|
||||
<>
|
||||
<FormattedError>{error ?? 'unknown'}</FormattedError>
|
||||
<div className="w-full my-4">
|
||||
<Button
|
||||
onClick={() => {
|
||||
dialog.hide('introspection-failed');
|
||||
refetch();
|
||||
}}
|
||||
className="ml-auto"
|
||||
color="primary"
|
||||
size="sm"
|
||||
>
|
||||
Try Again
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{error ? 'Introspection Failed' : 'Introspecting'}
|
||||
</Button>
|
||||
</div>,
|
||||
];
|
||||
|
||||
return actions;
|
||||
}, [dialog, error, isLoading, refetch]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full grid grid-cols-1 grid-rows-[minmax(0,100%)_auto]">
|
||||
<Editor
|
||||
@@ -81,47 +128,7 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi
|
||||
onChange={handleChangeQuery}
|
||||
placeholder="..."
|
||||
ref={editorViewRef}
|
||||
actions={
|
||||
error || isLoading
|
||||
? [
|
||||
<div key="introspection" className="!opacity-100">
|
||||
<Button
|
||||
key="introspection"
|
||||
size="xs"
|
||||
color={error ? 'danger' : 'secondary'}
|
||||
isLoading={isLoading}
|
||||
onClick={() => {
|
||||
dialog.show({
|
||||
title: 'Introspection Failed',
|
||||
size: 'dynamic',
|
||||
id: 'introspection-failed',
|
||||
render: () => (
|
||||
<>
|
||||
<FormattedError>{error ?? 'unknown'}</FormattedError>
|
||||
<div className="w-full my-4">
|
||||
<Button
|
||||
onClick={() => {
|
||||
dialog.hide('introspection-failed');
|
||||
refetch();
|
||||
}}
|
||||
className="ml-auto"
|
||||
color="primary"
|
||||
size="sm"
|
||||
>
|
||||
Try Again
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{error ? 'Introspection Failed' : 'Introspecting'}
|
||||
</Button>
|
||||
</div>,
|
||||
]
|
||||
: []
|
||||
}
|
||||
actions={actions}
|
||||
{...extraEditorProps}
|
||||
/>
|
||||
<div className="grid grid-rows-[auto_minmax(0,1fr)] grid-cols-1 min-h-[5rem]">
|
||||
|
||||
@@ -17,14 +17,16 @@ interface Props {
|
||||
style: CSSProperties;
|
||||
}
|
||||
|
||||
const emptyArray: string[] = [];
|
||||
|
||||
export function GrpcConnectionLayout({ style }: Props) {
|
||||
const activeRequest = useActiveRequest('grpc_request');
|
||||
const updateRequest = useUpdateGrpcRequest(activeRequest?.id ?? null);
|
||||
const { mutateAsync: updateRequest } = useUpdateGrpcRequest(activeRequest?.id ?? null);
|
||||
const connections = useGrpcConnections(activeRequest?.id ?? null);
|
||||
const activeConnection = connections[0] ?? null;
|
||||
const messages = useGrpcEvents(activeConnection?.id ?? null);
|
||||
const protoFilesKv = useGrpcProtoFiles(activeRequest?.id ?? null);
|
||||
const protoFiles = protoFilesKv.value ?? [];
|
||||
const protoFiles = protoFilesKv.value ?? emptyArray;
|
||||
const grpc = useGrpc(activeRequest, activeConnection, protoFiles);
|
||||
|
||||
const services = grpc.reflect.data ?? null;
|
||||
@@ -32,7 +34,7 @@ export function GrpcConnectionLayout({ style }: Props) {
|
||||
if (services == null || activeRequest == null) return;
|
||||
const s = services.find((s) => s.name === activeRequest.service);
|
||||
if (s == null) {
|
||||
updateRequest.mutate({
|
||||
updateRequest({
|
||||
service: services[0]?.name ?? null,
|
||||
method: services[0]?.methods[0]?.name ?? null,
|
||||
});
|
||||
@@ -41,7 +43,7 @@ export function GrpcConnectionLayout({ style }: Props) {
|
||||
|
||||
const m = s.methods.find((m) => m.name === activeRequest.method);
|
||||
if (m == null) {
|
||||
updateRequest.mutate({ method: s.methods[0]?.name ?? null });
|
||||
updateRequest({ method: s.methods[0]?.name ?? null });
|
||||
return;
|
||||
}
|
||||
}, [activeRequest, services, updateRequest]);
|
||||
@@ -84,6 +86,7 @@ export function GrpcConnectionLayout({ style }: Props) {
|
||||
activeRequest={activeRequest}
|
||||
protoFiles={protoFiles}
|
||||
methodType={methodType}
|
||||
isStreaming={grpc.isStreaming}
|
||||
onGo={grpc.go.mutate}
|
||||
onCommit={grpc.commit.mutate}
|
||||
onCancel={grpc.cancel.mutate}
|
||||
|
||||
@@ -6,6 +6,8 @@ import { useGrpcEvents } from '../hooks/useGrpcEvents';
|
||||
import { usePinnedGrpcConnection } from '../hooks/usePinnedGrpcConnection';
|
||||
import { useStateWithDeps } from '../hooks/useStateWithDeps';
|
||||
import type { GrpcEvent, GrpcRequest } from '../lib/models';
|
||||
import { isResponseLoading } from '../lib/models';
|
||||
import { Banner } from './core/Banner';
|
||||
import { Button } from './core/Button';
|
||||
import { Icon } from './core/Icon';
|
||||
import { JsonAttributeTree } from './core/JsonAttributeTree';
|
||||
@@ -64,7 +66,7 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
||||
<HStack className="pl-3 mb-1 font-mono">
|
||||
<HStack space={2}>
|
||||
<span>{events.length} messages</span>
|
||||
{activeConnection.elapsed === 0 && (
|
||||
{isResponseLoading(activeConnection) && (
|
||||
<Icon icon="refresh" size="sm" spin className="text-fg-subtler" />
|
||||
)}
|
||||
</HStack>
|
||||
@@ -75,6 +77,11 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
||||
/>
|
||||
</HStack>
|
||||
<div className="overflow-y-auto h-full">
|
||||
{activeConnection.error && (
|
||||
<Banner color="danger" className="m-3">
|
||||
{activeConnection.error}
|
||||
</Banner>
|
||||
)}
|
||||
{...events.map((e) => (
|
||||
<EventRow
|
||||
key={e.id}
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { CSSProperties } from 'react';
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { createGlobalState } from 'react-use';
|
||||
import type { ReflectResponseService } from '../hooks/useGrpc';
|
||||
import { useGrpcConnections } from '../hooks/useGrpcConnections';
|
||||
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
|
||||
import { useUpdateGrpcRequest } from '../hooks/useUpdateGrpcRequest';
|
||||
import type { GrpcMetadataEntry, GrpcRequest } from '../lib/models';
|
||||
@@ -37,6 +36,7 @@ interface Props {
|
||||
| 'streaming'
|
||||
| 'no-schema'
|
||||
| 'no-method';
|
||||
isStreaming: boolean;
|
||||
onCommit: () => void;
|
||||
onCancel: () => void;
|
||||
onSend: (v: { message: string }) => void;
|
||||
@@ -54,15 +54,13 @@ export function GrpcConnectionSetupPane({
|
||||
protoFiles,
|
||||
reflectionError,
|
||||
reflectionLoading,
|
||||
isStreaming,
|
||||
onGo,
|
||||
onCommit,
|
||||
onCancel,
|
||||
onSend,
|
||||
}: Props) {
|
||||
const connections = useGrpcConnections(activeRequest.id ?? null);
|
||||
const updateRequest = useUpdateGrpcRequest(activeRequest?.id ?? null);
|
||||
const activeConnection = connections[0] ?? null;
|
||||
const isStreaming = activeConnection?.elapsed === 0;
|
||||
const [activeTab, setActiveTab] = useActiveTab();
|
||||
const { updateKey: forceUpdateKey } = useRequestUpdateKey(activeRequest.id ?? null);
|
||||
|
||||
@@ -78,7 +76,9 @@ export function GrpcConnectionSetupPane({
|
||||
);
|
||||
|
||||
const handleChangeMessage = useCallback(
|
||||
(message: string) => updateRequest.mutateAsync({ message }),
|
||||
(message: string) => {
|
||||
return updateRequest.mutateAsync({ message });
|
||||
},
|
||||
[updateRequest],
|
||||
);
|
||||
|
||||
@@ -221,14 +221,14 @@ export function GrpcConnectionSetupPane({
|
||||
{isStreaming && (
|
||||
<>
|
||||
<IconButton
|
||||
className="border border-background-highlight-secondary"
|
||||
variant="border"
|
||||
size="sm"
|
||||
title="Cancel"
|
||||
onClick={onCancel}
|
||||
icon="x"
|
||||
/>
|
||||
<IconButton
|
||||
className="border border-background-highlight-secondary"
|
||||
variant="border"
|
||||
size="sm"
|
||||
title="Commit"
|
||||
onClick={onCommit}
|
||||
@@ -237,8 +237,8 @@ export function GrpcConnectionSetupPane({
|
||||
</>
|
||||
)}
|
||||
<IconButton
|
||||
className="border border-background-highlight-secondary"
|
||||
size="sm"
|
||||
variant="border"
|
||||
title={isStreaming ? 'Connect' : 'Send'}
|
||||
hotkeyAction="grpc_request.send"
|
||||
onClick={isStreaming ? handleSend : handleConnect}
|
||||
@@ -247,8 +247,8 @@ export function GrpcConnectionSetupPane({
|
||||
</>
|
||||
) : (
|
||||
<IconButton
|
||||
className="border border-background-highlight-secondary"
|
||||
size="sm"
|
||||
variant="border"
|
||||
title={methodType === 'unary' ? 'Send' : 'Connect'}
|
||||
hotkeyAction="grpc_request.send"
|
||||
onClick={isStreaming ? onCancel : handleConnect}
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
handleRefresh,
|
||||
jsonCompletion,
|
||||
jsonSchemaLinter,
|
||||
stateExtensions,
|
||||
updateSchema,
|
||||
stateExtensions,
|
||||
} from 'codemirror-json-schema';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { useAlert } from '../hooks/useAlert';
|
||||
@@ -41,6 +41,7 @@ export function GrpcEditor({
|
||||
...extraEditorProps
|
||||
}: Props) {
|
||||
const editorViewRef = useRef<EditorView>(null);
|
||||
|
||||
const alert = useAlert();
|
||||
const dialog = useDialog();
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useGrpcRequest } from '../hooks/useGrpcRequest';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { Banner } from './core/Banner';
|
||||
import { Button } from './core/Button';
|
||||
import { FormattedError } from './core/FormattedError';
|
||||
import { IconButton } from './core/IconButton';
|
||||
import { InlineCode } from './core/InlineCode';
|
||||
import { Link } from './core/Link';
|
||||
@@ -129,7 +128,14 @@ export function GrpcProtoSelection({ requestId }: Props) {
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
{reflectError && <FormattedError>{reflectError}</FormattedError>}
|
||||
{reflectError && (
|
||||
<Banner color="warning">
|
||||
<h1 className="font-bold">
|
||||
Reflection failed on URL <InlineCode>{request.url}</InlineCode>
|
||||
</h1>
|
||||
{reflectError}
|
||||
</Banner>
|
||||
)}
|
||||
{reflectionUnimplemented && protoFiles.length === 0 && (
|
||||
<Banner>
|
||||
<InlineCode>{request.url}</InlineCode> doesn't implement{' '}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import React, { useState } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { useThemes } from '../../hooks/useThemes';
|
||||
import { capitalize } from '../../lib/capitalize';
|
||||
import { invokeCmd } from '../../lib/tauri';
|
||||
import { yaakDark } from '../../lib/theme/themes/yaak';
|
||||
import { getThemeCSS } from '../../lib/theme/window';
|
||||
import { Banner } from '../core/Banner';
|
||||
@@ -58,11 +58,11 @@ export function SettingsDesign() {
|
||||
const coreThemeCSS = [yaakDark].map(getThemeCSS).join('\n\n');
|
||||
|
||||
try {
|
||||
await invoke('cmd_write_file_dev', {
|
||||
await invokeCmd('cmd_write_file_dev', {
|
||||
pathname: exportDir + '/themes-all.css',
|
||||
contents: allThemesCSS,
|
||||
});
|
||||
await invoke('cmd_write_file_dev', {
|
||||
await invokeCmd('cmd_write_file_dev', {
|
||||
pathname: exportDir + '/themes-slim.css',
|
||||
contents: coreThemeCSS,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import { useRef } from 'react';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
@@ -8,6 +7,7 @@ import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
||||
import { useExportData } from '../hooks/useExportData';
|
||||
import { useImportData } from '../hooks/useImportData';
|
||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import type { DropdownRef } from './core/Dropdown';
|
||||
import { Dropdown } from './core/Dropdown';
|
||||
import { Icon } from './core/Icon';
|
||||
@@ -27,7 +27,7 @@ export function SettingsDropdown() {
|
||||
|
||||
const showSettings = async () => {
|
||||
if (!workspaceId) return;
|
||||
await invoke('cmd_new_nested_window', {
|
||||
await invokeCmd('cmd_new_nested_window', {
|
||||
url: routes.paths.workspaceSettings({ workspaceId }),
|
||||
label: 'settings',
|
||||
title: 'Yaak Settings',
|
||||
|
||||
@@ -838,7 +838,7 @@ const SidebarItem = forwardRef(function SidebarItem(
|
||||
</div>
|
||||
{latestGrpcConnection ? (
|
||||
<div className="ml-auto">
|
||||
{latestGrpcConnection.elapsed === 0 && (
|
||||
{isResponseLoading(latestGrpcConnection) && (
|
||||
<Icon spin size="sm" icon="update" className="text-fg-subtler" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
@apply text-fg pl-1 pr-1.5;
|
||||
@apply w-full; /* Important! Ensure it spans the entire width */
|
||||
@apply w-full text-fg pl-1 pr-1.5;
|
||||
}
|
||||
|
||||
.cm-placeholder {
|
||||
@@ -207,7 +208,7 @@
|
||||
/* NOTE: Extra selector required to override default styles */
|
||||
.cm-tooltip.cm-tooltip-autocomplete,
|
||||
.cm-tooltip.cm-completionInfo {
|
||||
@apply shadow-lg bg-background rounded text-fg-subtle border border-background-highlight z-50 pointer-events-auto text-sm;
|
||||
@apply shadow-lg bg-background rounded text-fg-subtle border border-background-highlight z-50 pointer-events-auto text-editor;
|
||||
|
||||
.cm-completionIcon {
|
||||
@apply italic font-mono;
|
||||
@@ -285,7 +286,7 @@
|
||||
}
|
||||
|
||||
& > ul > li {
|
||||
@apply cursor-default px-2 py-1.5 rounded-sm text-fg-subtle flex items-center;
|
||||
@apply cursor-default px-2 h-[2em] rounded-sm text-fg flex items-center;
|
||||
}
|
||||
|
||||
& > ul > li[aria-selected] {
|
||||
@@ -297,11 +298,11 @@
|
||||
}
|
||||
|
||||
.cm-completionLabel {
|
||||
@apply text-fg-subtle;
|
||||
@apply text-fg;
|
||||
}
|
||||
|
||||
.cm-completionDetail {
|
||||
@apply ml-auto pl-6;
|
||||
@apply ml-auto pl-6 text-fg-subtle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +242,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
size="sm"
|
||||
title="Reformat contents"
|
||||
icon="magicWand"
|
||||
variant="border"
|
||||
className={classNames(actionClassName)}
|
||||
onClick={() => {
|
||||
if (cm.current === null) return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export interface AppInfo {
|
||||
isDev: boolean;
|
||||
@@ -13,7 +13,7 @@ export function useAppInfo() {
|
||||
return useQuery({
|
||||
queryKey: ['appInfo'],
|
||||
queryFn: async () => {
|
||||
const metadata = await invoke('cmd_metadata');
|
||||
const metadata = await invokeCmd('cmd_metadata');
|
||||
return metadata as AppInfo;
|
||||
},
|
||||
}).data;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useAppInfo } from './useAppInfo';
|
||||
|
||||
@@ -10,7 +10,7 @@ export function useCheckForUpdates() {
|
||||
const appInfo = useAppInfo();
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
const hasUpdate: boolean = await minPromiseMillis(invoke('cmd_check_for_updates'), 500);
|
||||
const hasUpdate: boolean = await minPromiseMillis(invokeCmd('cmd_check_for_updates'), 500);
|
||||
if (!hasUpdate) {
|
||||
alert({
|
||||
id: 'no-updates',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function cookieJarsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
@@ -15,7 +15,7 @@ export function useCookieJars() {
|
||||
queryKey: cookieJarsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_cookie_jars', { workspaceId })) as CookieJar[];
|
||||
return (await invokeCmd('cmd_list_cookie_jars', { workspaceId })) as CookieJar[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useClipboardText } from './useClipboardText';
|
||||
|
||||
@@ -6,7 +6,7 @@ export function useCopyAsCurl(requestId: string) {
|
||||
const [, copy] = useClipboardText();
|
||||
const environmentId = useActiveEnvironmentId();
|
||||
return async () => {
|
||||
const cmd: string = await invoke('cmd_request_to_curl', { requestId, environmentId });
|
||||
const cmd: string = await invokeCmd('cmd_request_to_curl', { requestId, environmentId });
|
||||
copy(cmd);
|
||||
return cmd;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
import { usePrompt } from './usePrompt';
|
||||
@@ -24,7 +24,7 @@ export function useCreateCookieJar() {
|
||||
label: 'Name',
|
||||
defaultValue: 'My Jar',
|
||||
});
|
||||
return invoke('cmd_create_cookie_jar', { workspaceId, name });
|
||||
return invokeCmd('cmd_create_cookie_jar', { workspaceId, name });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'create'),
|
||||
onSuccess: async (cookieJar) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Environment } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
@@ -24,7 +24,7 @@ export function useCreateEnvironment() {
|
||||
placeholder: 'My Environment',
|
||||
defaultValue: 'My Environment',
|
||||
});
|
||||
return invoke('cmd_create_environment', { name, variables: [], workspaceId });
|
||||
return invokeCmd('cmd_create_environment', { name, variables: [], workspaceId });
|
||||
},
|
||||
onSettled: () => trackEvent('environment', 'create'),
|
||||
onSuccess: async (environment) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Folder } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
@@ -31,7 +31,7 @@ export function useCreateFolder() {
|
||||
}));
|
||||
patch.sortPriority = patch.sortPriority || -Date.now();
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invoke('cmd_create_folder', { workspaceId, ...patch });
|
||||
return invokeCmd('cmd_create_folder', { workspaceId, ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
@@ -32,7 +32,7 @@ export function useCreateGrpcRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invoke('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
|
||||
return invokeCmd('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveRequest } from './useActiveRequest';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
@@ -28,7 +28,7 @@ export function useCreateHttpRequest() {
|
||||
}
|
||||
}
|
||||
patch.folderId = patch.folderId || activeRequest?.folderId;
|
||||
return invoke('cmd_create_http_request', { request: { workspaceId, ...patch } });
|
||||
return invokeCmd('cmd_create_http_request', { request: { workspaceId, ...patch } });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { usePrompt } from './usePrompt';
|
||||
|
||||
@@ -18,7 +18,7 @@ export function useCreateWorkspace() {
|
||||
confirmLabel: 'Create',
|
||||
placeholder: 'My Workspace',
|
||||
});
|
||||
return invoke('cmd_create_workspace', { name });
|
||||
return invokeCmd('cmd_create_workspace', { name });
|
||||
},
|
||||
onSuccess: async (workspace) => {
|
||||
routes.navigate('workspace', { workspaceId: workspace.id });
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
@@ -28,7 +28,7 @@ export function useDeleteAnyGrpcRequest() {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_grpc_request', { requestId: id });
|
||||
return invokeCmd('cmd_delete_grpc_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'delete'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
@@ -29,7 +29,7 @@ export function useDeleteAnyHttpRequest() {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_http_request', { requestId: id });
|
||||
return invokeCmd('cmd_delete_http_request', { requestId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'delete'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
|
||||
@@ -23,7 +23,7 @@ export function useDeleteCookieJar(cookieJar: CookieJar | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
return invokeCmd('cmd_delete_cookie_jar', { cookieJarId: cookieJar?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('cookie_jar', 'delete'),
|
||||
onSuccess: async (cookieJar) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Environment, Workspace } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
|
||||
@@ -23,7 +23,7 @@ export function useDeleteEnvironment(environment: Environment | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_environment', { environmentId: environment?.id });
|
||||
return invokeCmd('cmd_delete_environment', { environmentId: environment?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('environment', 'delete'),
|
||||
onSuccess: async (environment) => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Folder } from '../lib/models';
|
||||
import { getFolder } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useConfirm } from './useConfirm';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
@@ -26,7 +26,7 @@ export function useDeleteFolder(id: string | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_folder', { folderId: id });
|
||||
return invokeCmd('cmd_delete_folder', { folderId: id });
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'delete'),
|
||||
onSuccess: async (folder) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { GrpcConnection } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnection(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<GrpcConnection>({
|
||||
mutationFn: async () => {
|
||||
return await invoke('cmd_delete_grpc_connection', { id: id });
|
||||
return await invokeCmd('cmd_delete_grpc_connection', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_connection', 'delete'),
|
||||
onSuccess: ({ requestId, id: connectionId }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcConnectionsQueryKey } from './useGrpcConnections';
|
||||
|
||||
export function useDeleteGrpcConnections(requestId?: string) {
|
||||
@@ -8,7 +8,7 @@ export function useDeleteGrpcConnections(requestId?: string) {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (requestId === undefined) return;
|
||||
await invoke('cmd_delete_all_grpc_connections', { requestId });
|
||||
await invokeCmd('cmd_delete_all_grpc_connections', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_connection', 'delete_many'),
|
||||
onSuccess: async () => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteHttpResponse(id: string | null) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<HttpResponse>({
|
||||
mutationFn: async () => {
|
||||
return await invoke('cmd_delete_http_response', { id: id });
|
||||
return await invokeCmd('cmd_delete_http_response', { id: id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_response', 'delete'),
|
||||
onSuccess: ({ requestId, id: responseId }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||
|
||||
export function useDeleteHttpResponses(requestId?: string) {
|
||||
@@ -8,7 +8,7 @@ export function useDeleteHttpResponses(requestId?: string) {
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (requestId === undefined) return;
|
||||
await invoke('cmd_delete_all_http_responses', { requestId });
|
||||
await invokeCmd('cmd_delete_all_http_responses', { requestId });
|
||||
},
|
||||
onSettled: () => trackEvent('http_response', 'delete_many'),
|
||||
onSuccess: async () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { InlineCode } from '../components/core/InlineCode';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { useConfirm } from './useConfirm';
|
||||
@@ -28,7 +28,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
),
|
||||
});
|
||||
if (!confirmed) return null;
|
||||
return invoke('cmd_delete_workspace', { workspaceId: workspace?.id });
|
||||
return invokeCmd('cmd_delete_workspace', { workspaceId: workspace?.id });
|
||||
},
|
||||
onSettled: () => trackEvent('workspace', 'delete'),
|
||||
onSuccess: async (workspace) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { setKeyValue } from '../lib/keyValueStore';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
@@ -22,7 +22,7 @@ export function useDuplicateGrpcRequest({
|
||||
return useMutation<GrpcRequest, string>({
|
||||
mutationFn: async () => {
|
||||
if (id === null) throw new Error("Can't duplicate a null grpc request");
|
||||
return invoke('cmd_duplicate_grpc_request', { id });
|
||||
return invokeCmd('cmd_duplicate_grpc_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('grpc_request', 'duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
@@ -19,7 +19,7 @@ export function useDuplicateHttpRequest({
|
||||
return useMutation<HttpRequest, string>({
|
||||
mutationFn: async () => {
|
||||
if (id === null) throw new Error("Can't duplicate a null request");
|
||||
return invoke('cmd_duplicate_http_request', { id });
|
||||
return invokeCmd('cmd_duplicate_http_request', { id });
|
||||
},
|
||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||
onSuccess: async (request) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Environment } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function environmentsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
@@ -15,7 +15,7 @@ export function useEnvironments() {
|
||||
queryKey: environmentsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_environments', { workspaceId })) as Environment[];
|
||||
return (await invokeCmd('cmd_list_environments', { workspaceId })) as Environment[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useFilterResponse({
|
||||
responseId,
|
||||
@@ -16,7 +16,7 @@ export function useFilterResponse({
|
||||
return null;
|
||||
}
|
||||
|
||||
return (await invoke('cmd_filter_response', { responseId, filter })) as string | null;
|
||||
return (await invokeCmd('cmd_filter_response', { responseId, filter })) as string | null;
|
||||
},
|
||||
}).data ?? ''
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Folder } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function foldersQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
@@ -15,7 +15,7 @@ export function useFolders() {
|
||||
queryKey: foldersQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_folders', { workspaceId })) as Folder[];
|
||||
return (await invokeCmd('cmd_list_folders', { workspaceId })) as Folder[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { emit } from '@tauri-apps/api/event';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import type { GrpcConnection, GrpcRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
|
||||
@@ -21,7 +21,8 @@ export function useGrpc(
|
||||
const environmentId = useActiveEnvironmentId();
|
||||
|
||||
const go = useMutation<void, string>({
|
||||
mutationFn: async () => await invoke('cmd_grpc_go', { requestId, environmentId, protoFiles }),
|
||||
mutationFn: async () =>
|
||||
await invokeCmd('cmd_grpc_go', { requestId, environmentId, protoFiles }),
|
||||
onSettled: () => trackEvent('grpc_request', 'send'),
|
||||
});
|
||||
|
||||
@@ -43,25 +44,26 @@ export function useGrpc(
|
||||
onSettled: () => trackEvent('grpc_connection', 'commit'),
|
||||
});
|
||||
|
||||
const debouncedUrl = useDebouncedValue<string>(req?.url ?? 'n/a', 500);
|
||||
const debouncedUrl = useDebouncedValue<string>(req?.url ?? '', 1000);
|
||||
const debouncedMessage = useDebouncedValue<string>(req?.message ?? '', 1000);
|
||||
|
||||
const reflect = useQuery<ReflectResponseService[], string>({
|
||||
enabled: req != null,
|
||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, protoFiles],
|
||||
refetchOnWindowFocus: false,
|
||||
queryFn: async () => {
|
||||
return (await minPromiseMillis(
|
||||
invoke('cmd_grpc_reflect', { requestId, protoFiles }),
|
||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, debouncedMessage, protoFiles],
|
||||
queryFn: async () =>
|
||||
(await minPromiseMillis(
|
||||
invokeCmd('cmd_grpc_reflect', { requestId, protoFiles }),
|
||||
300,
|
||||
)) as ReflectResponseService[];
|
||||
},
|
||||
)) as ReflectResponseService[],
|
||||
});
|
||||
|
||||
console.log('CONN', conn);
|
||||
return {
|
||||
go,
|
||||
reflect,
|
||||
cancel,
|
||||
commit,
|
||||
isStreaming: conn?.elapsed === 0,
|
||||
isStreaming: conn != null && conn.elapsed === 0,
|
||||
send,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { GrpcConnection } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function grpcConnectionsQueryKey({ requestId }: { requestId: string }) {
|
||||
return ['grpc_connections', { requestId }];
|
||||
@@ -13,7 +13,7 @@ export function useGrpcConnections(requestId: string | null) {
|
||||
initialData: [],
|
||||
queryKey: grpcConnectionsQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_grpc_connections', {
|
||||
return (await invokeCmd('cmd_list_grpc_connections', {
|
||||
requestId,
|
||||
limit: 200,
|
||||
})) as GrpcConnection[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { GrpcEvent } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function grpcEventsQueryKey({ connectionId }: { connectionId: string }) {
|
||||
return ['grpc_events', { connectionId }];
|
||||
@@ -13,7 +13,7 @@ export function useGrpcEvents(connectionId: string | null) {
|
||||
initialData: [],
|
||||
queryKey: grpcEventsQueryKey({ connectionId: connectionId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_grpc_events', {
|
||||
return (await invokeCmd('cmd_list_grpc_events', {
|
||||
connectionId,
|
||||
limit: 200,
|
||||
})) as GrpcEvent[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
@@ -15,7 +15,7 @@ export function useGrpcRequests() {
|
||||
queryKey: grpcRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
|
||||
return (await invokeCmd('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
|
||||
export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
|
||||
@@ -15,7 +15,7 @@ export function useHttpRequests() {
|
||||
queryKey: httpRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
if (workspaceId == null) return [];
|
||||
return (await invoke('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
|
||||
return (await invokeCmd('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function httpResponsesQueryKey({ requestId }: { requestId: string }) {
|
||||
return ['http_responses', { requestId }];
|
||||
@@ -13,7 +13,7 @@ export function useHttpResponses(requestId: string | null) {
|
||||
initialData: [],
|
||||
queryKey: httpResponsesQueryKey({ requestId: requestId ?? 'n/a' }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_http_responses', {
|
||||
return (await invokeCmd('cmd_list_http_responses', {
|
||||
requestId,
|
||||
limit: 200,
|
||||
})) as HttpResponse[];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useRequestUpdateKey } from './useRequestUpdateKey';
|
||||
import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
|
||||
@@ -17,7 +17,7 @@ export function useImportCurl({ clearClipboard }: { clearClipboard?: boolean } =
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ requestId, command }: { requestId: string | null; command: string }) => {
|
||||
const request: Record<string, unknown> = await invoke('cmd_curl_to_request', {
|
||||
const request: Record<string, unknown> = await invokeCmd('cmd_curl_to_request', {
|
||||
command,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { Button } from '../components/core/Button';
|
||||
import { FormattedError } from '../components/core/FormattedError';
|
||||
@@ -7,6 +6,7 @@ import { VStack } from '../components/core/Stacks';
|
||||
import { useDialog } from '../components/DialogContext';
|
||||
import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '../lib/models';
|
||||
import { count } from '../lib/pluralize';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
@@ -33,7 +33,7 @@ export function useImportData() {
|
||||
folders: Folder[];
|
||||
httpRequests: HttpRequest[];
|
||||
grpcRequests: GrpcRequest[];
|
||||
} = await invoke('cmd_import_data', {
|
||||
} = await invokeCmd('cmd_import_data', {
|
||||
filePath: selected.path,
|
||||
workspaceId: activeWorkspaceId,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { IntrospectionQuery } from 'graphql';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
@@ -8,6 +7,7 @@ import { getResponseBodyText } from '../lib/responseBody';
|
||||
import { sendEphemeralRequest } from '../lib/sendEphemeralRequest';
|
||||
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
|
||||
import { useDebouncedValue } from './useDebouncedValue';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
const introspectionRequestBody = JSON.stringify({
|
||||
query: getIntrospectionQuery(),
|
||||
@@ -22,9 +22,12 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||
const [refetchKey, setRefetchKey] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>();
|
||||
const [introspection, setIntrospection] = useLocalStorage<IntrospectionQuery | null>(
|
||||
`introspection:${baseRequest.id}`,
|
||||
);
|
||||
|
||||
const { value: introspection, set: setIntrospection } = useKeyValue<IntrospectionQuery | null>({
|
||||
key: ['graphql_introspection', baseRequest.id],
|
||||
fallback: null,
|
||||
namespace: 'global',
|
||||
});
|
||||
|
||||
const introspectionInterval = useRef<NodeJS.Timeout>();
|
||||
|
||||
@@ -40,31 +43,26 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||
const response = await minPromiseMillis(sendEphemeralRequest(args, activeEnvironmentId), 700);
|
||||
|
||||
if (response.error) {
|
||||
return Promise.reject(new Error(response.error));
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
const bodyText = await getResponseBodyText(response);
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
return Promise.reject(
|
||||
new Error(`Request failed with status ${response.status}.\n\n${bodyText}`),
|
||||
);
|
||||
throw new Error(`Request failed with status ${response.status}.\n\n${bodyText}`);
|
||||
}
|
||||
|
||||
if (bodyText === null) {
|
||||
return Promise.reject(new Error('Empty body returned in response'));
|
||||
throw new Error('Empty body returned in response');
|
||||
}
|
||||
|
||||
const { data } = JSON.parse(bodyText);
|
||||
console.log('Introspection response', data);
|
||||
setIntrospection(data);
|
||||
await setIntrospection(data);
|
||||
};
|
||||
|
||||
const runIntrospection = () => {
|
||||
fetchIntrospection()
|
||||
.catch((e) => {
|
||||
setIntrospection(null);
|
||||
setError(e.message);
|
||||
})
|
||||
.catch((e) => setError(e.message))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import { Button } from '../components/core/Button';
|
||||
import { useToast } from '../components/ToastContext';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useListenToTauriEvent } from './useListenToTauriEvent';
|
||||
|
||||
export function useNotificationToast() {
|
||||
const toast = useToast();
|
||||
|
||||
const markRead = (id: string) => {
|
||||
invoke('cmd_dismiss_notification', { notificationId: id }).catch(console.error);
|
||||
invokeCmd('cmd_dismiss_notification', { notificationId: id }).catch(console.error);
|
||||
};
|
||||
|
||||
useListenToTauriEvent<{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { getRecentEnvironments } from './useRecentEnvironments';
|
||||
import { getRecentRequests } from './useRecentRequests';
|
||||
@@ -26,7 +26,7 @@ export function useOpenWorkspace() {
|
||||
requestId,
|
||||
})
|
||||
: routes.paths.workspace({ workspaceId, environmentId });
|
||||
await invoke('cmd_new_window', { url: path });
|
||||
await invokeCmd('cmd_new_window', { url: path });
|
||||
} else {
|
||||
const environmentId = (await getRecentEnvironments(workspaceId))[0];
|
||||
const requestId = (await getRecentRequests(workspaceId))[0];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import mime from 'mime';
|
||||
import slugify from 'slugify';
|
||||
@@ -8,6 +7,7 @@ import { useToast } from '../components/ToastContext';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { getContentTypeHeader } from '../lib/models';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useSaveResponse(response: HttpResponse) {
|
||||
const toast = useToast();
|
||||
@@ -24,7 +24,7 @@ export function useSaveResponse(response: HttpResponse) {
|
||||
defaultPath: ext ? `${slug}.${ext}` : slug,
|
||||
title: 'Save Response',
|
||||
});
|
||||
await invoke('cmd_save_response', { responseId: response.id, filepath });
|
||||
await invokeCmd('cmd_save_response', { responseId: response.id, filepath });
|
||||
toast.show({
|
||||
message: (
|
||||
<>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import slugify from 'slugify';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useActiveCookieJar } from './useActiveCookieJar';
|
||||
import { useActiveEnvironment } from './useActiveEnvironment';
|
||||
import { useAlert } from './useAlert';
|
||||
@@ -31,7 +31,7 @@ export function useSendAnyRequest(options: { download?: boolean } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
return invoke('cmd_send_http_request', {
|
||||
return invokeCmd('cmd_send_http_request', {
|
||||
requestId: id,
|
||||
environmentId: environment?.id,
|
||||
downloadDir: downloadDir,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Settings } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function settingsQueryKey() {
|
||||
return ['settings'];
|
||||
@@ -11,7 +11,7 @@ export function useSettings() {
|
||||
useQuery({
|
||||
queryKey: settingsQueryKey(),
|
||||
queryFn: async () => {
|
||||
const settings = (await invoke('cmd_get_settings')) as Settings;
|
||||
const settings = (await invokeCmd('cmd_get_settings')) as Settings;
|
||||
return [settings];
|
||||
},
|
||||
}).data?.[0] ?? undefined
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Folder } from '../lib/models';
|
||||
import { getFolder } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { foldersQueryKey } from './useFolders';
|
||||
|
||||
export function useUpdateAnyFolder() {
|
||||
@@ -14,7 +14,7 @@ export function useUpdateAnyFolder() {
|
||||
throw new Error("Can't update a null folder");
|
||||
}
|
||||
|
||||
await invoke('cmd_update_folder', { folder: update(folder) });
|
||||
await invokeCmd('cmd_update_folder', { folder: update(folder) });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const folder = await getFolder(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { GrpcRequest } from '../lib/models';
|
||||
import { getGrpcRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||
|
||||
export function useUpdateAnyGrpcRequest() {
|
||||
@@ -20,7 +20,7 @@ export function useUpdateAnyGrpcRequest() {
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invoke('cmd_update_grpc_request', { request: patchedRequest });
|
||||
await invokeCmd('cmd_update_grpc_request', { request: patchedRequest });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getGrpcRequest(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { HttpRequest } from '../lib/models';
|
||||
import { getHttpRequest } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||
|
||||
export function useUpdateAnyHttpRequest() {
|
||||
@@ -20,7 +20,7 @@ export function useUpdateAnyHttpRequest() {
|
||||
|
||||
const patchedRequest =
|
||||
typeof update === 'function' ? update(request) : { ...request, ...update };
|
||||
await invoke('cmd_update_http_request', { request: patchedRequest });
|
||||
await invokeCmd('cmd_update_http_request', { request: patchedRequest });
|
||||
},
|
||||
onMutate: async ({ id, update }) => {
|
||||
const request = await getHttpRequest(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { CookieJar } from '../lib/models';
|
||||
import { getCookieJar } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { cookieJarsQueryKey } from './useCookieJars';
|
||||
|
||||
export function useUpdateCookieJar(id: string | null) {
|
||||
@@ -15,7 +15,7 @@ export function useUpdateCookieJar(id: string | null) {
|
||||
|
||||
const newCookieJar = typeof v === 'function' ? v(cookieJar) : { ...cookieJar, ...v };
|
||||
console.log('NEW COOKIE JAR', newCookieJar.cookies.length);
|
||||
await invoke('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||
await invokeCmd('cmd_update_cookie_jar', { cookieJar: newCookieJar });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const cookieJar = await getCookieJar(id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Environment } from '../lib/models';
|
||||
import { getEnvironment } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { environmentsQueryKey } from './useEnvironments';
|
||||
|
||||
export function useUpdateEnvironment(id: string | null) {
|
||||
@@ -14,7 +14,7 @@ export function useUpdateEnvironment(id: string | null) {
|
||||
}
|
||||
|
||||
const newEnvironment = typeof v === 'function' ? v(environment) : { ...environment, ...v };
|
||||
await invoke('cmd_update_environment', { environment: newEnvironment });
|
||||
await invokeCmd('cmd_update_environment', { environment: newEnvironment });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const environment = await getEnvironment(id);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Settings } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { useSettings } from './useSettings';
|
||||
|
||||
export function useUpdateSettings() {
|
||||
@@ -10,7 +10,7 @@ export function useUpdateSettings() {
|
||||
mutationFn: async (patch) => {
|
||||
if (settings == null) return;
|
||||
const newSettings: Settings = { ...settings, ...patch };
|
||||
await invoke('cmd_update_settings', { settings: newSettings });
|
||||
await invokeCmd('cmd_update_settings', { settings: newSettings });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { getWorkspace } from '../lib/store';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
import { workspacesQueryKey } from './useWorkspaces';
|
||||
|
||||
export function useUpdateWorkspace(id: string | null) {
|
||||
@@ -14,7 +14,7 @@ export function useUpdateWorkspace(id: string | null) {
|
||||
}
|
||||
|
||||
const newWorkspace = typeof v === 'function' ? v(workspace) : { ...workspace, ...v };
|
||||
await invoke('cmd_update_workspace', { workspace: newWorkspace });
|
||||
await invokeCmd('cmd_update_workspace', { workspace: newWorkspace });
|
||||
},
|
||||
onMutate: async (v) => {
|
||||
const workspace = await getWorkspace(id);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { EnvironmentVariable } from '../lib/models';
|
||||
|
||||
export function variablesQueryKey({ environmentId }: { environmentId: string }) {
|
||||
return ['variables', { environmentId }];
|
||||
}
|
||||
|
||||
export function useVariables({ environmentId }: { environmentId: string }) {
|
||||
return (
|
||||
useQuery({
|
||||
queryKey: variablesQueryKey({ environmentId }),
|
||||
queryFn: async () => {
|
||||
return (await invoke('cmd_list_variables', { environmentId })) as EnvironmentVariable[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { Workspace } from '../lib/models';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/ban-types
|
||||
export function workspacesQueryKey(_?: {}) {
|
||||
@@ -12,7 +12,7 @@ export function useWorkspaces() {
|
||||
useQuery({
|
||||
queryKey: workspacesQueryKey(),
|
||||
queryFn: async () => {
|
||||
const workspaces = await invoke('cmd_list_workspaces');
|
||||
const workspaces = await invokeCmd('cmd_list_workspaces');
|
||||
return workspaces as Workspace[];
|
||||
},
|
||||
}).data ?? []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export type TrackResource =
|
||||
| 'appearance'
|
||||
@@ -37,7 +37,7 @@ export function trackEvent(
|
||||
action: TrackAction,
|
||||
attributes: Record<string, string | number> = {},
|
||||
) {
|
||||
invoke('cmd_track_event', {
|
||||
invokeCmd('cmd_track_event', {
|
||||
resource: resource,
|
||||
action,
|
||||
attributes,
|
||||
|
||||
@@ -3,31 +3,25 @@ import type { GrpcRequest, HttpRequest } from './models';
|
||||
export function fallbackRequestName(r: HttpRequest | GrpcRequest | null): string {
|
||||
if (r == null) return '';
|
||||
|
||||
// Return name if it has one
|
||||
if (r.name) {
|
||||
return r.name;
|
||||
}
|
||||
|
||||
const withoutVariables = r.url.replace(/\$\{\[\s*([^\]]+)\s*]}/g, '$1');
|
||||
// Replace variable syntax with variable name
|
||||
const withoutVariables = r.url.replace(/\$\{\[\s*([^\]\s]+)\s*]}/g, '$1');
|
||||
if (withoutVariables.trim() === '') {
|
||||
return r.model === 'http_request' ? 'New HTTP Request' : 'new gRPC Request';
|
||||
}
|
||||
|
||||
const fixedUrl = withoutVariables.match(/^https?:\/\//)
|
||||
? withoutVariables
|
||||
: 'http://' + withoutVariables;
|
||||
|
||||
// GRPC gets nice short names
|
||||
if (r.model === 'grpc_request' && r.service != null && r.method != null) {
|
||||
const shortService = r.service.split('.').pop();
|
||||
return `${shortService}/${r.method}`;
|
||||
} else {
|
||||
try {
|
||||
const url = new URL(fixedUrl);
|
||||
const pathname = url.pathname === '/' ? '' : url.pathname;
|
||||
return `${url.host}${pathname}`;
|
||||
} catch (_) {
|
||||
// Nothing
|
||||
}
|
||||
}
|
||||
|
||||
return r.url;
|
||||
// Strip unnecessary protocol
|
||||
const withoutProto = withoutVariables.replace(/^https?:\/\//, '');
|
||||
|
||||
return withoutProto;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { KeyValue } from './models';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export async function setKeyValue<T>({
|
||||
namespace = 'global',
|
||||
@@ -10,7 +10,7 @@ export async function setKeyValue<T>({
|
||||
key: string | string[];
|
||||
value: T;
|
||||
}): Promise<void> {
|
||||
await invoke('cmd_set_key_value', {
|
||||
await invokeCmd('cmd_set_key_value', {
|
||||
namespace,
|
||||
key: buildKeyValueKey(key),
|
||||
value: JSON.stringify(value),
|
||||
@@ -26,7 +26,7 @@ export async function getKeyValue<T>({
|
||||
key: string | string[];
|
||||
fallback: T;
|
||||
}) {
|
||||
const kv = (await invoke('cmd_get_key_value', {
|
||||
const kv = (await invokeCmd('cmd_get_key_value', {
|
||||
namespace,
|
||||
key: buildKeyValueKey(key),
|
||||
})) as KeyValue | null;
|
||||
|
||||
@@ -207,7 +207,7 @@ export interface HttpResponse extends BaseModel {
|
||||
readonly headers: HttpHeader[];
|
||||
}
|
||||
|
||||
export function isResponseLoading(response: HttpResponse): boolean {
|
||||
export function isResponseLoading(response: HttpResponse | GrpcConnection): boolean {
|
||||
return response.elapsed === 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { HttpRequest, HttpResponse } from './models';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export async function sendEphemeralRequest(
|
||||
request: HttpRequest,
|
||||
@@ -7,5 +7,5 @@ export async function sendEphemeralRequest(
|
||||
): Promise<HttpResponse> {
|
||||
// Remove some things that we don't want to associate
|
||||
const newRequest = { ...request };
|
||||
return invoke('cmd_send_ephemeral_request', { request: newRequest, environmentId });
|
||||
return invokeCmd('cmd_send_ephemeral_request', { request: newRequest, environmentId });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type {
|
||||
CookieJar,
|
||||
Environment,
|
||||
@@ -8,14 +7,15 @@ import type {
|
||||
Settings,
|
||||
Workspace,
|
||||
} from './models';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
export async function getSettings(): Promise<Settings> {
|
||||
return invoke('cmd_get_settings', {});
|
||||
return invokeCmd('cmd_get_settings', {});
|
||||
}
|
||||
|
||||
export async function getGrpcRequest(id: string | null): Promise<GrpcRequest | null> {
|
||||
if (id === null) return null;
|
||||
const request: GrpcRequest = (await invoke('cmd_get_grpc_request', { id })) ?? null;
|
||||
const request: GrpcRequest = (await invokeCmd('cmd_get_grpc_request', { id })) ?? null;
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export async function getGrpcRequest(id: string | null): Promise<GrpcRequest | n
|
||||
|
||||
export async function getHttpRequest(id: string | null): Promise<HttpRequest | null> {
|
||||
if (id === null) return null;
|
||||
const request: HttpRequest = (await invoke('cmd_get_http_request', { id })) ?? null;
|
||||
const request: HttpRequest = (await invokeCmd('cmd_get_http_request', { id })) ?? null;
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export async function getHttpRequest(id: string | null): Promise<HttpRequest | n
|
||||
|
||||
export async function getEnvironment(id: string | null): Promise<Environment | null> {
|
||||
if (id === null) return null;
|
||||
const environment: Environment = (await invoke('cmd_get_environment', { id })) ?? null;
|
||||
const environment: Environment = (await invokeCmd('cmd_get_environment', { id })) ?? null;
|
||||
if (environment == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ export async function getEnvironment(id: string | null): Promise<Environment | n
|
||||
|
||||
export async function getFolder(id: string | null): Promise<Folder | null> {
|
||||
if (id === null) return null;
|
||||
const folder: Folder = (await invoke('cmd_get_folder', { id })) ?? null;
|
||||
const folder: Folder = (await invokeCmd('cmd_get_folder', { id })) ?? null;
|
||||
if (folder == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export async function getFolder(id: string | null): Promise<Folder | null> {
|
||||
|
||||
export async function getWorkspace(id: string | null): Promise<Workspace | null> {
|
||||
if (id === null) return null;
|
||||
const workspace: Workspace = (await invoke('cmd_get_workspace', { id })) ?? null;
|
||||
const workspace: Workspace = (await invokeCmd('cmd_get_workspace', { id })) ?? null;
|
||||
if (workspace == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export async function getWorkspace(id: string | null): Promise<Workspace | null>
|
||||
|
||||
export async function getCookieJar(id: string | null): Promise<CookieJar | null> {
|
||||
if (id === null) return null;
|
||||
const cookieJar: CookieJar = (await invoke('cmd_get_cookie_jar', { id })) ?? null;
|
||||
const cookieJar: CookieJar = (await invokeCmd('cmd_get_cookie_jar', { id })) ?? null;
|
||||
if (cookieJar == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
70
src-web/lib/tauri.ts
Normal file
70
src-web/lib/tauri.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { InvokeArgs } from '@tauri-apps/api/core';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
type TauriCmd =
|
||||
| 'cmd_check_for_updates'
|
||||
| 'cmd_create_cookie_jar'
|
||||
| 'cmd_create_environment'
|
||||
| 'cmd_create_folder'
|
||||
| 'cmd_create_grpc_request'
|
||||
| 'cmd_create_http_request'
|
||||
| 'cmd_create_workspace'
|
||||
| 'cmd_curl_to_request'
|
||||
| 'cmd_delete_all_grpc_connections'
|
||||
| 'cmd_delete_all_http_responses'
|
||||
| 'cmd_delete_cookie_jar'
|
||||
| 'cmd_delete_environment'
|
||||
| 'cmd_delete_folder'
|
||||
| 'cmd_delete_grpc_connection'
|
||||
| 'cmd_delete_grpc_request'
|
||||
| 'cmd_delete_http_request'
|
||||
| 'cmd_delete_http_response'
|
||||
| 'cmd_delete_workspace'
|
||||
| 'cmd_duplicate_grpc_request'
|
||||
| 'cmd_duplicate_http_request'
|
||||
| 'cmd_export_data'
|
||||
| 'cmd_filter_response'
|
||||
| 'cmd_get_cookie_jar'
|
||||
| 'cmd_get_environment'
|
||||
| 'cmd_get_folder'
|
||||
| 'cmd_get_grpc_request'
|
||||
| 'cmd_get_http_request'
|
||||
| 'cmd_get_key_value'
|
||||
| 'cmd_get_settings'
|
||||
| 'cmd_get_workspace'
|
||||
| 'cmd_grpc_go'
|
||||
| 'cmd_grpc_reflect'
|
||||
| 'cmd_import_data'
|
||||
| 'cmd_list_cookie_jars'
|
||||
| 'cmd_list_environments'
|
||||
| 'cmd_list_folders'
|
||||
| 'cmd_list_grpc_connections'
|
||||
| 'cmd_list_grpc_events'
|
||||
| 'cmd_list_grpc_requests'
|
||||
| 'cmd_list_http_requests'
|
||||
| 'cmd_list_http_responses'
|
||||
| 'cmd_list_workspaces'
|
||||
| 'cmd_metadata'
|
||||
| 'cmd_new_nested_window'
|
||||
| 'cmd_new_window'
|
||||
| 'cmd_request_to_curl'
|
||||
| 'cmd_dismiss_notification'
|
||||
| 'cmd_save_response'
|
||||
| 'cmd_send_ephemeral_request'
|
||||
| 'cmd_send_http_request'
|
||||
| 'cmd_set_key_value'
|
||||
| 'cmd_set_update_mode'
|
||||
| 'cmd_track_event'
|
||||
| 'cmd_update_cookie_jar'
|
||||
| 'cmd_update_environment'
|
||||
| 'cmd_update_folder'
|
||||
| 'cmd_update_grpc_request'
|
||||
| 'cmd_update_http_request'
|
||||
| 'cmd_update_settings'
|
||||
| 'cmd_update_workspace'
|
||||
| 'cmd_write_file_dev';
|
||||
|
||||
export async function invokeCmd<T>(cmd: TauriCmd, args?: InvokeArgs): Promise<T> {
|
||||
// console.log('RUN COMMAND', cmd, args);
|
||||
return invoke(cmd, args);
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import { getCurrent } from '@tauri-apps/api/webviewWindow';
|
||||
import { type } from '@tauri-apps/plugin-os';
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { pdfjs } from 'react-pdf';
|
||||
import { attachConsole } from 'tauri-plugin-log-api';
|
||||
import { App } from './components/App';
|
||||
import './main.css';
|
||||
import { pdfjs } from 'react-pdf';
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/build/pdf.worker.min.mjs',
|
||||
|
||||
Reference in New Issue
Block a user