Show gRPC requests in sidebar

This commit is contained in:
Gregory Schier
2024-02-03 13:08:24 -08:00
parent d8d5344d21
commit dc077209cc
33 changed files with 389 additions and 149 deletions

View File

@@ -1,8 +1,8 @@
use log::{debug, warn}; use log::{debug, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use sqlx::{Pool, Sqlite};
use sqlx::types::JsonValue; use sqlx::types::JsonValue;
use sqlx::{Pool, Sqlite};
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
use crate::{is_dev, models}; use crate::{is_dev, models};
@@ -15,6 +15,7 @@ pub enum AnalyticsResource {
Dialog, Dialog,
Environment, Environment,
Folder, Folder,
GrpcRequest,
HttpRequest, HttpRequest,
HttpResponse, HttpResponse,
KeyValue, KeyValue,
@@ -30,6 +31,7 @@ impl AnalyticsResource {
"CookieJar" => Some(AnalyticsResource::CookieJar), "CookieJar" => Some(AnalyticsResource::CookieJar),
"Environment" => Some(AnalyticsResource::Environment), "Environment" => Some(AnalyticsResource::Environment),
"Folder" => Some(AnalyticsResource::Folder), "Folder" => Some(AnalyticsResource::Folder),
"GrpcRequest" => Some(AnalyticsResource::GrpcRequest),
"HttpRequest" => Some(AnalyticsResource::HttpRequest), "HttpRequest" => Some(AnalyticsResource::HttpRequest),
"HttpResponse" => Some(AnalyticsResource::HttpResponse), "HttpResponse" => Some(AnalyticsResource::HttpResponse),
"KeyValue" => Some(AnalyticsResource::KeyValue), "KeyValue" => Some(AnalyticsResource::KeyValue),
@@ -89,6 +91,7 @@ fn resource_name(resource: AnalyticsResource) -> &'static str {
AnalyticsResource::Dialog => "dialog", AnalyticsResource::Dialog => "dialog",
AnalyticsResource::Environment => "environment", AnalyticsResource::Environment => "environment",
AnalyticsResource::Folder => "folder", AnalyticsResource::Folder => "folder",
AnalyticsResource::GrpcRequest => "grpc_request",
AnalyticsResource::HttpRequest => "http_request", AnalyticsResource::HttpRequest => "http_request",
AnalyticsResource::HttpResponse => "http_response", AnalyticsResource::HttpResponse => "http_response",
AnalyticsResource::KeyValue => "key_value", AnalyticsResource::KeyValue => "key_value",

View File

@@ -44,13 +44,14 @@ use crate::http::send_http_request;
use crate::models::{ use crate::models::{
cancel_pending_responses, create_response, delete_all_responses, delete_cookie_jar, cancel_pending_responses, create_response, delete_all_responses, delete_cookie_jar,
delete_environment, delete_folder, delete_request, delete_response, delete_workspace, delete_environment, delete_folder, delete_request, delete_response, delete_workspace,
duplicate_request, find_cookie_jars, find_environments, find_folders, find_requests, duplicate_grpc_request, duplicate_http_request, list_cookie_jars, list_folders, list_requests,
find_responses, find_workspaces, generate_id, get_cookie_jar, get_environment, get_folder, list_responses, list_workspaces, generate_id, get_cookie_jar, get_environment, get_folder,
get_http_request, get_key_value_raw, get_or_create_settings, get_response, get_workspace, get_grpc_request, get_http_request, get_key_value_raw, get_or_create_settings, get_response,
get_workspace_export_resources, set_key_value_raw, update_response_if_id, update_settings, get_workspace, get_workspace_export_resources, list_environments, list_grpc_requests,
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_request, upsert_workspace, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar,
CookieJar, Environment, EnvironmentVariable, Folder, HttpRequest, HttpResponse, KeyValue, upsert_environment, upsert_folder, upsert_grpc_request, upsert_http_request, upsert_workspace,
Settings, Workspace, CookieJar, Environment, EnvironmentVariable, Folder, GrpcRequest, HttpRequest, HttpResponse,
KeyValue, Settings, Workspace,
}; };
use crate::plugin::{ImportResources, ImportResult}; use crate::plugin::{ImportResources, ImportResult};
use crate::updates::{update_mode_from_str, UpdateMode, YaakUpdater}; use crate::updates::{update_mode_from_str, UpdateMode, YaakUpdater};
@@ -467,7 +468,7 @@ async fn cmd_import_data(
} }
for r in r.resources.requests { for r in r.resources.requests {
let x = upsert_request(db, r) let x = upsert_http_request(db, r)
.await .await
.expect("Failed to create request"); .expect("Failed to create request");
imported_resources.requests.push(x.clone()); imported_resources.requests.push(x.clone());
@@ -747,7 +748,46 @@ async fn cmd_create_environment(
} }
#[tauri::command] #[tauri::command]
async fn cmd_create_request( async fn cmd_create_grpc_request(
workspace_id: &str,
name: &str,
sort_priority: f64,
folder_id: Option<&str>,
window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<GrpcRequest, String> {
let db = &*db_state.lock().await;
let created = upsert_grpc_request(
db,
&GrpcRequest {
workspace_id: workspace_id.to_string(),
name: name.to_string(),
folder_id: folder_id.map(|s| s.to_string()),
sort_priority,
..Default::default()
},
)
.await
.expect("Failed to create grpc request");
emit_and_return(&window, "created_model", created)
}
#[tauri::command]
async fn cmd_duplicate_grpc_request(
id: &str,
window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<GrpcRequest, String> {
let db = &*db_state.lock().await;
let request = duplicate_grpc_request(db, id)
.await
.expect("Failed to duplicate grpc request");
emit_and_return(&window, "updated_model", request)
}
#[tauri::command]
async fn cmd_create_http_request(
workspace_id: &str, workspace_id: &str,
name: &str, name: &str,
sort_priority: f64, sort_priority: f64,
@@ -756,7 +796,7 @@ async fn cmd_create_request(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<HttpRequest, String> { ) -> Result<HttpRequest, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let created_request = upsert_request( let created_request = upsert_http_request(
db, db,
HttpRequest { HttpRequest {
workspace_id: workspace_id.to_string(), workspace_id: workspace_id.to_string(),
@@ -768,21 +808,21 @@ async fn cmd_create_request(
}, },
) )
.await .await
.expect("Failed to create request"); .expect("Failed to create http request");
emit_and_return(&window, "created_model", created_request) emit_and_return(&window, "created_model", created_request)
} }
#[tauri::command] #[tauri::command]
async fn cmd_duplicate_request( async fn cmd_duplicate_http_request(
id: &str, id: &str,
window: Window<Wry>, window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<HttpRequest, String> { ) -> Result<HttpRequest, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let request = duplicate_request(db, id) let request = duplicate_http_request(db, id)
.await .await
.expect("Failed to duplicate request"); .expect("Failed to duplicate http request");
emit_and_return(&window, "updated_model", request) emit_and_return(&window, "updated_model", request)
} }
@@ -815,20 +855,46 @@ async fn cmd_update_environment(
} }
#[tauri::command] #[tauri::command]
async fn cmd_update_request( async fn cmd_update_grpc_request(
request: GrpcRequest,
window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<GrpcRequest, String> {
let db = &*db_state.lock().await;
let updated_request = upsert_grpc_request(db, &request)
.await
.expect("Failed to update grpc request");
emit_and_return(&window, "updated_model", updated_request)
}
#[tauri::command]
async fn cmd_update_http_request(
request: HttpRequest, request: HttpRequest,
window: Window<Wry>, window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<HttpRequest, String> { ) -> Result<HttpRequest, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let updated_request = upsert_request(db, request) let updated_request = upsert_http_request(db, request)
.await .await
.expect("Failed to update request"); .expect("Failed to update request");
emit_and_return(&window, "updated_model", updated_request) emit_and_return(&window, "updated_model", updated_request)
} }
#[tauri::command] #[tauri::command]
async fn cmd_delete_request( async fn cmd_delete_grpc_request(
window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
request_id: &str,
) -> Result<HttpRequest, String> {
let db = &*db_state.lock().await;
let req = delete_request(db, request_id)
.await
.expect("Failed to delete request");
emit_and_return(&window, "deleted_model", req)
}
#[tauri::command]
async fn cmd_delete_http_request(
window: Window<Wry>, window: Window<Wry>,
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
request_id: &str, request_id: &str,
@@ -846,7 +912,7 @@ async fn cmd_list_folders(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<Folder>, String> { ) -> Result<Vec<Folder>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
find_folders(db, workspace_id) list_folders(db, workspace_id)
.await .await
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
@@ -917,12 +983,25 @@ async fn cmd_delete_environment(
} }
#[tauri::command] #[tauri::command]
async fn cmd_list_requests( async fn cmd_list_grpc_requests(
workspace_id: &str,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<GrpcRequest>, String> {
let db = &*db_state.lock().await;
let requests = list_grpc_requests(db, workspace_id)
.await
.expect("Failed to find grpc requests");
// .map_err(|e| e.to_string())
Ok(requests)
}
#[tauri::command]
async fn cmd_list_http_requests(
workspace_id: &str, workspace_id: &str,
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<HttpRequest>, String> { ) -> Result<Vec<HttpRequest>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let requests = find_requests(db, workspace_id) let requests = list_requests(db, workspace_id)
.await .await
.expect("Failed to find requests"); .expect("Failed to find requests");
// .map_err(|e| e.to_string()) // .map_err(|e| e.to_string())
@@ -935,7 +1014,7 @@ async fn cmd_list_environments(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<Environment>, String> { ) -> Result<Vec<Environment>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let environments = find_environments(db, workspace_id) let environments = list_environments(db, workspace_id)
.await .await
.expect("Failed to find environments"); .expect("Failed to find environments");
@@ -972,7 +1051,16 @@ async fn cmd_get_folder(
} }
#[tauri::command] #[tauri::command]
async fn cmd_get_request( async fn cmd_get_grpc_request(
id: &str,
db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<GrpcRequest, String> {
let db = &*db_state.lock().await;
get_grpc_request(db, id).await.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_get_http_request(
id: &str, id: &str,
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<HttpRequest, String> { ) -> Result<HttpRequest, String> {
@@ -995,7 +1083,7 @@ async fn cmd_list_cookie_jars(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<CookieJar>, String> { ) -> Result<Vec<CookieJar>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let cookie_jars = find_cookie_jars(db, workspace_id) let cookie_jars = list_cookie_jars(db, workspace_id)
.await .await
.expect("Failed to find cookie jars"); .expect("Failed to find cookie jars");
@@ -1041,7 +1129,7 @@ async fn cmd_list_responses(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<HttpResponse>, String> { ) -> Result<Vec<HttpResponse>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
find_responses(db, request_id, limit) list_responses(db, request_id, limit)
.await .await
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
@@ -1075,7 +1163,7 @@ async fn cmd_list_workspaces(
db_state: State<'_, Mutex<Pool<Sqlite>>>, db_state: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<Vec<Workspace>, String> { ) -> Result<Vec<Workspace>, String> {
let db = &*db_state.lock().await; let db = &*db_state.lock().await;
let workspaces = find_workspaces(db) let workspaces = list_workspaces(db)
.await .await
.expect("Failed to find workspaces"); .expect("Failed to find workspaces");
if workspaces.is_empty() { if workspaces.is_empty() {
@@ -1203,23 +1291,26 @@ fn main() {
cmd_create_cookie_jar, cmd_create_cookie_jar,
cmd_create_environment, cmd_create_environment,
cmd_create_folder, cmd_create_folder,
cmd_create_request, cmd_create_grpc_request,
cmd_create_http_request,
cmd_create_workspace, cmd_create_workspace,
cmd_delete_all_responses, cmd_delete_all_responses,
cmd_delete_cookie_jar, cmd_delete_cookie_jar,
cmd_delete_environment, cmd_delete_environment,
cmd_delete_folder, cmd_delete_folder,
cmd_delete_request, cmd_delete_grpc_request,
cmd_delete_http_request,
cmd_delete_response, cmd_delete_response,
cmd_delete_workspace, cmd_delete_workspace,
cmd_duplicate_request, cmd_duplicate_http_request,
cmd_export_data, cmd_export_data,
cmd_filter_response, cmd_filter_response,
cmd_get_cookie_jar, cmd_get_cookie_jar,
cmd_get_environment, cmd_get_environment,
cmd_get_folder, cmd_get_folder,
cmd_get_key_value, cmd_get_key_value,
cmd_get_request, cmd_get_http_request,
cmd_get_grpc_request,
cmd_get_settings, cmd_get_settings,
cmd_get_workspace, cmd_get_workspace,
cmd_grpc_call_unary, cmd_grpc_call_unary,
@@ -1231,7 +1322,8 @@ fn main() {
cmd_list_cookie_jars, cmd_list_cookie_jars,
cmd_list_environments, cmd_list_environments,
cmd_list_folders, cmd_list_folders,
cmd_list_requests, cmd_list_http_requests,
cmd_list_grpc_requests,
cmd_list_responses, cmd_list_responses,
cmd_list_workspaces, cmd_list_workspaces,
cmd_new_window, cmd_new_window,
@@ -1243,7 +1335,8 @@ fn main() {
cmd_update_cookie_jar, cmd_update_cookie_jar,
cmd_update_environment, cmd_update_environment,
cmd_update_folder, cmd_update_folder,
cmd_update_request, cmd_update_grpc_request,
cmd_update_http_request,
cmd_update_settings, cmd_update_settings,
cmd_update_workspace, cmd_update_workspace,
]) ])

View File

@@ -355,7 +355,7 @@ pub async fn get_key_value_raw(db: &Pool<Sqlite>, namespace: &str, key: &str) ->
.ok() .ok()
} }
pub async fn find_workspaces(db: &Pool<Sqlite>) -> Result<Vec<Workspace>, sqlx::Error> { pub async fn list_workspaces(db: &Pool<Sqlite>) -> Result<Vec<Workspace>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as!(
Workspace, Workspace,
r#" r#"
@@ -398,7 +398,7 @@ pub async fn delete_workspace(db: &Pool<Sqlite>, id: &str) -> Result<Workspace,
.execute(db) .execute(db)
.await; .await;
for r in find_responses_by_workspace_id(db, id).await? { for r in list_responses_by_workspace_id(db, id).await? {
delete_response(db, &r.id).await?; delete_response(db, &r.id).await?;
} }
@@ -420,7 +420,7 @@ pub async fn get_cookie_jar(db: &Pool<Sqlite>, id: &str) -> Result<CookieJar, sq
.await .await
} }
pub async fn find_cookie_jars( pub async fn list_cookie_jars(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
workspace_id: &str, workspace_id: &str,
) -> Result<Vec<CookieJar>, sqlx::Error> { ) -> Result<Vec<CookieJar>, sqlx::Error> {
@@ -454,6 +454,15 @@ pub async fn delete_cookie_jar(db: &Pool<Sqlite>, id: &str) -> Result<CookieJar,
Ok(cookie_jar) Ok(cookie_jar)
} }
pub async fn duplicate_grpc_request(
db: &Pool<Sqlite>,
id: &str,
) -> Result<GrpcRequest, sqlx::Error> {
let mut request = get_grpc_request(db, id).await?.clone();
request.id = "".to_string();
upsert_grpc_request(db, &request).await
}
pub async fn upsert_grpc_request( pub async fn upsert_grpc_request(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
request: &GrpcRequest, request: &GrpcRequest,
@@ -687,7 +696,7 @@ pub async fn upsert_cookie_jar(
get_cookie_jar(db, &id).await get_cookie_jar(db, &id).await
} }
pub async fn find_environments( pub async fn list_environments(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
workspace_id: &str, workspace_id: &str,
) -> Result<Vec<Environment>, sqlx::Error> { ) -> Result<Vec<Environment>, sqlx::Error> {
@@ -832,7 +841,7 @@ pub async fn get_folder(db: &Pool<Sqlite>, id: &str) -> Result<Folder, sqlx::Err
.await .await
} }
pub async fn find_folders( pub async fn list_folders(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
workspace_id: &str, workspace_id: &str,
) -> Result<Vec<Folder>, sqlx::Error> { ) -> Result<Vec<Folder>, sqlx::Error> {
@@ -896,13 +905,19 @@ pub async fn upsert_folder(db: &Pool<Sqlite>, r: Folder) -> Result<Folder, sqlx:
get_folder(db, &id).await get_folder(db, &id).await
} }
pub async fn duplicate_request(db: &Pool<Sqlite>, id: &str) -> Result<HttpRequest, sqlx::Error> { pub async fn duplicate_http_request(
db: &Pool<Sqlite>,
id: &str,
) -> Result<HttpRequest, sqlx::Error> {
let mut request = get_http_request(db, id).await?.clone(); let mut request = get_http_request(db, id).await?.clone();
request.id = "".to_string(); request.id = "".to_string();
upsert_request(db, request).await upsert_http_request(db, request).await
} }
pub async fn upsert_request(db: &Pool<Sqlite>, r: HttpRequest) -> Result<HttpRequest, sqlx::Error> { pub async fn upsert_http_request(
db: &Pool<Sqlite>,
r: HttpRequest,
) -> Result<HttpRequest, sqlx::Error> {
let id = match r.id.as_str() { let id = match r.id.as_str() {
"" => generate_id(Some("rq")), "" => generate_id(Some("rq")),
_ => r.id.to_string(), _ => r.id.to_string(),
@@ -952,7 +967,7 @@ pub async fn upsert_request(db: &Pool<Sqlite>, r: HttpRequest) -> Result<HttpReq
get_http_request(db, &id).await get_http_request(db, &id).await
} }
pub async fn find_requests( pub async fn list_requests(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
workspace_id: &str, workspace_id: &str,
) -> Result<Vec<HttpRequest>, sqlx::Error> { ) -> Result<Vec<HttpRequest>, sqlx::Error> {
@@ -1171,7 +1186,7 @@ pub async fn get_response(db: &Pool<Sqlite>, id: &str) -> Result<HttpResponse, s
.await .await
} }
pub async fn find_responses( pub async fn list_responses(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
request_id: &str, request_id: &str,
limit: Option<i64>, limit: Option<i64>,
@@ -1197,7 +1212,7 @@ pub async fn find_responses(
.await .await
} }
pub async fn find_responses_by_workspace_id( pub async fn list_responses_by_workspace_id(
db: &Pool<Sqlite>, db: &Pool<Sqlite>,
workspace_id: &str, workspace_id: &str,
) -> Result<Vec<HttpResponse>, sqlx::Error> { ) -> Result<Vec<HttpResponse>, sqlx::Error> {
@@ -1243,7 +1258,7 @@ pub async fn delete_response(db: &Pool<Sqlite>, id: &str) -> Result<HttpResponse
} }
pub async fn delete_all_responses(db: &Pool<Sqlite>, request_id: &str) -> Result<(), sqlx::Error> { pub async fn delete_all_responses(db: &Pool<Sqlite>, request_id: &str) -> Result<(), sqlx::Error> {
for r in find_responses(db, request_id, None).await? { for r in list_responses(db, request_id, None).await? {
delete_response(db, &r.id).await?; delete_response(db, &r.id).await?;
} }
Ok(()) Ok(())
@@ -1289,13 +1304,13 @@ pub async fn get_workspace_export_resources(
timestamp: chrono::Utc::now().naive_utc(), timestamp: chrono::Utc::now().naive_utc(),
resources: WorkspaceExportResources { resources: WorkspaceExportResources {
workspaces: vec![workspace], workspaces: vec![workspace],
environments: find_environments(db, workspace_id) environments: list_environments(db, workspace_id)
.await .await
.expect("Failed to get environments"), .expect("Failed to get environments"),
folders: find_folders(db, workspace_id) folders: list_folders(db, workspace_id)
.await .await
.expect("Failed to get folders"), .expect("Failed to get folders"),
requests: find_requests(db, workspace_id) requests: list_requests(db, workspace_id)
.await .await
.expect("Failed to get requests"), .expect("Failed to get requests"),
}, },

View File

@@ -1,7 +1,7 @@
import { createBrowserRouter, Navigate, Outlet, RouterProvider } from 'react-router-dom'; import { createBrowserRouter, Navigate, Outlet, RouterProvider } from 'react-router-dom';
import { routePaths, useAppRoutes } from '../hooks/useAppRoutes'; import { routePaths, useAppRoutes } from '../hooks/useAppRoutes';
import { useRecentRequests } from '../hooks/useRecentRequests'; import { useRecentRequests } from '../hooks/useRecentRequests';
import { useRequests } from '../hooks/useRequests'; import { useHttpRequests } from '../hooks/useHttpRequests';
import { GlobalHooks } from './GlobalHooks'; import { GlobalHooks } from './GlobalHooks';
import Workspace from './Workspace'; import Workspace from './Workspace';
import Workspaces from './Workspaces'; import Workspaces from './Workspaces';
@@ -49,7 +49,7 @@ export function AppRouter() {
function WorkspaceOrRedirect() { function WorkspaceOrRedirect() {
const recentRequests = useRecentRequests(); const recentRequests = useRecentRequests();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const requests = useRequests(); const requests = useHttpRequests();
const request = requests.find((r) => r.id === recentRequests[0]); const request = requests.find((r) => r.id === recentRequests[0]);
const routes = useAppRoutes(); const routes = useAppRoutes();

View File

@@ -1,4 +1,4 @@
import { useUpdateRequest } from '../hooks/useUpdateRequest'; import { useUpdateHttpRequest } from '../hooks/useUpdateHttpRequest';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { Input } from './core/Input'; import { Input } from './core/Input';
import { VStack } from './core/Stacks'; import { VStack } from './core/Stacks';
@@ -9,7 +9,7 @@ interface Props {
} }
export function BasicAuth({ requestId, authentication }: Props) { export function BasicAuth({ requestId, authentication }: Props) {
const updateRequest = useUpdateRequest(requestId); const updateRequest = useUpdateHttpRequest(requestId);
return ( return (
<VStack className="my-2" space={2}> <VStack className="my-2" space={2}>

View File

@@ -1,4 +1,4 @@
import { useUpdateRequest } from '../hooks/useUpdateRequest'; import { useUpdateHttpRequest } from '../hooks/useUpdateHttpRequest';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { Input } from './core/Input'; import { Input } from './core/Input';
import { VStack } from './core/Stacks'; import { VStack } from './core/Stacks';
@@ -9,7 +9,7 @@ interface Props {
} }
export function BearerAuth({ requestId, authentication }: Props) { export function BearerAuth({ requestId, authentication }: Props) {
const updateRequest = useUpdateRequest(requestId); const updateRequest = useUpdateHttpRequest(requestId);
return ( return (
<VStack className="my-2" space={2}> <VStack className="my-2" space={2}>

View File

@@ -8,7 +8,7 @@ import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
import { useRecentEnvironments } from '../hooks/useRecentEnvironments'; import { useRecentEnvironments } from '../hooks/useRecentEnvironments';
import { useRecentRequests } from '../hooks/useRecentRequests'; import { useRecentRequests } from '../hooks/useRecentRequests';
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces'; import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
import { requestsQueryKey } from '../hooks/useRequests'; import { httpRequestsQueryKey } from '../hooks/useHttpRequests';
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
import { responsesQueryKey } from '../hooks/useResponses'; import { responsesQueryKey } from '../hooks/useResponses';
import { settingsQueryKey } from '../hooks/useSettings'; import { settingsQueryKey } from '../hooks/useSettings';
@@ -47,7 +47,7 @@ export function GlobalHooks() {
const queryKey = const queryKey =
payload.model === 'http_request' payload.model === 'http_request'
? requestsQueryKey(payload) ? httpRequestsQueryKey(payload)
: payload.model === 'http_response' : payload.model === 'http_response'
? responsesQueryKey(payload) ? responsesQueryKey(payload)
: payload.model === 'workspace' : payload.model === 'workspace'
@@ -76,7 +76,7 @@ export function GlobalHooks() {
const queryKey = const queryKey =
payload.model === 'http_request' payload.model === 'http_request'
? requestsQueryKey(payload) ? httpRequestsQueryKey(payload)
: payload.model === 'http_response' : payload.model === 'http_response'
? responsesQueryKey(payload) ? responsesQueryKey(payload)
: payload.model === 'workspace' : payload.model === 'workspace'
@@ -115,7 +115,7 @@ export function GlobalHooks() {
if (payload.model === 'workspace') { if (payload.model === 'workspace') {
queryClient.setQueryData<Workspace[]>(workspacesQueryKey(), removeById(payload)); queryClient.setQueryData<Workspace[]>(workspacesQueryKey(), removeById(payload));
} else if (payload.model === 'http_request') { } else if (payload.model === 'http_request') {
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey(payload), removeById(payload)); queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey(payload), removeById(payload));
} else if (payload.model === 'http_response') { } else if (payload.model === 'http_response') {
queryClient.setQueryData<HttpResponse[]>(responsesQueryKey(payload), removeById(payload)); queryClient.setQueryData<HttpResponse[]>(responsesQueryKey(payload), removeById(payload));
} else if (payload.model === 'key_value') { } else if (payload.model === 'key_value') {

View File

@@ -208,7 +208,7 @@ export function GrpcConnectionLayout({ style }: Props) {
className="border border-highlight" className="border border-highlight"
size="sm" size="sm"
title="to-do" title="to-do"
hotkeyAction={grpc.isStreaming ? undefined : 'request.send'} hotkeyAction={grpc.isStreaming ? undefined : 'http_request.send'}
onClick={grpc.isStreaming ? handleCancel : handleConnect} onClick={grpc.isStreaming ? handleCancel : handleConnect}
icon={ icon={
grpc.isStreaming grpc.isStreaming
@@ -227,7 +227,7 @@ export function GrpcConnectionLayout({ style }: Props) {
className="border border-highlight" className="border border-highlight"
size="sm" size="sm"
title="to-do" title="to-do"
hotkeyAction="request.send" hotkeyAction="grpc_request.send"
onClick={() => grpc.send.mutateAsync({ message: message.value ?? '' })} onClick={() => grpc.send.mutateAsync({ message: message.value ?? '' })}
icon="sendHorizontal" icon="sendHorizontal"
/> />
@@ -331,7 +331,7 @@ export function GrpcConnectionLayout({ style }: Props) {
forceUpdateKey={resp} forceUpdateKey={resp}
/> />
) : ( ) : (
<HotKeyList hotkeys={['grpc.send', 'sidebar.toggle', 'urlBar.focus']} /> <HotKeyList hotkeys={['grpc_request.send', 'sidebar.toggle', 'urlBar.focus']} />
)} )}
</div> </div>
) )

View File

@@ -7,7 +7,7 @@ import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
import { useAppRoutes } from '../hooks/useAppRoutes'; import { useAppRoutes } from '../hooks/useAppRoutes';
import { useHotKey } from '../hooks/useHotKey'; import { useHotKey } from '../hooks/useHotKey';
import { useRecentRequests } from '../hooks/useRecentRequests'; import { useRecentRequests } from '../hooks/useRecentRequests';
import { useRequests } from '../hooks/useRequests'; import { useHttpRequests } from '../hooks/useHttpRequests';
import { fallbackRequestName } from '../lib/fallbackRequestName'; import { fallbackRequestName } from '../lib/fallbackRequestName';
import type { ButtonProps } from './core/Button'; import type { ButtonProps } from './core/Button';
import { Button } from './core/Button'; import { Button } from './core/Button';
@@ -19,7 +19,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest();
const activeWorkspaceId = useActiveWorkspaceId(); const activeWorkspaceId = useActiveWorkspaceId();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const requests = useRequests(); const requests = useHttpRequests();
const routes = useAppRoutes(); const routes = useAppRoutes();
const allRecentRequestIds = useRecentRequests(); const allRecentRequestIds = useRecentRequests();
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]); const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);

View File

@@ -6,7 +6,7 @@ import { useActiveRequest } from '../hooks/useActiveRequest';
import { useIsResponseLoading } from '../hooks/useIsResponseLoading'; import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
import { useSendRequest } from '../hooks/useSendRequest'; import { useSendRequest } from '../hooks/useSendRequest';
import { useUpdateRequest } from '../hooks/useUpdateRequest'; import { useUpdateHttpRequest } from '../hooks/useUpdateHttpRequest';
import { tryFormatJson } from '../lib/formatters'; import { tryFormatJson } from '../lib/formatters';
import type { HttpHeader, HttpRequest, HttpUrlParameter } from '../lib/models'; import type { HttpHeader, HttpRequest, HttpUrlParameter } from '../lib/models';
import { import {
@@ -43,9 +43,9 @@ interface Props {
const useActiveTab = createGlobalState<string>('body'); const useActiveTab = createGlobalState<string>('body');
export const RequestPane = memo(function RequestPane({ style, fullHeight, className }: Props) { export const RequestPane = memo(function RequestPane({ style, fullHeight, className }: Props) {
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest('http_request');
const activeRequestId = activeRequest?.id ?? null; const activeRequestId = activeRequest?.id ?? null;
const updateRequest = useUpdateRequest(activeRequestId); const updateRequest = useUpdateHttpRequest(activeRequestId);
const [activeTab, setActiveTab] = useActiveTab(); const [activeTab, setActiveTab] = useActiveTab();
const [forceUpdateHeaderEditorKey, setForceUpdateHeaderEditorKey] = useState<number>(0); const [forceUpdateHeaderEditorKey, setForceUpdateHeaderEditorKey] = useState<number>(0);
const { updateKey: forceUpdateKey } = useRequestUpdateKey(activeRequest?.id ?? null); const { updateKey: forceUpdateKey } = useRequestUpdateKey(activeRequest?.id ?? null);

View File

@@ -110,7 +110,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
<> <>
<span /> <span />
<HotKeyList <HotKeyList
hotkeys={['request.send', 'request.create', 'sidebar.toggle', 'urlBar.focus']} hotkeys={['http_request.send', 'http_request.create', 'sidebar.toggle', 'urlBar.focus']}
/> />
</> </>
)} )}

View File

@@ -11,26 +11,27 @@ import { useActiveRequestId } from '../hooks/useActiveRequestId';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes'; import { useAppRoutes } from '../hooks/useAppRoutes';
import { useCreateFolder } from '../hooks/useCreateFolder'; import { useCreateFolder } from '../hooks/useCreateFolder';
import { useCreateRequest } from '../hooks/useCreateRequest'; import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
import { useDeleteAnyRequest } from '../hooks/useDeleteAnyRequest'; import { useDeleteAnyRequest } from '../hooks/useDeleteAnyRequest';
import { useDeleteFolder } from '../hooks/useDeleteFolder'; import { useDeleteFolder } from '../hooks/useDeleteFolder';
import { useDeleteRequest } from '../hooks/useDeleteRequest'; import { useDeleteRequest } from '../hooks/useDeleteRequest';
import { useDuplicateRequest } from '../hooks/useDuplicateRequest'; import { useDuplicateRequest } from '../hooks/useDuplicateRequest';
import { useFolders } from '../hooks/useFolders'; import { useFolders } from '../hooks/useFolders';
import { useGrpcRequests } from '../hooks/useGrpcRequests';
import { useHotKey } from '../hooks/useHotKey'; import { useHotKey } from '../hooks/useHotKey';
import { useKeyValue } from '../hooks/useKeyValue'; import { useKeyValue } from '../hooks/useKeyValue';
import { useLatestResponse } from '../hooks/useLatestResponse'; import { useLatestResponse } from '../hooks/useLatestResponse';
import { usePrompt } from '../hooks/usePrompt'; import { usePrompt } from '../hooks/usePrompt';
import { useRequests } from '../hooks/useRequests'; import { useHttpRequests } from '../hooks/useHttpRequests';
import { useSendManyRequests } from '../hooks/useSendFolder'; import { useSendManyRequests } from '../hooks/useSendFolder';
import { useSendRequest } from '../hooks/useSendRequest'; import { useSendRequest } from '../hooks/useSendRequest';
import { useSidebarHidden } from '../hooks/useSidebarHidden'; import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder'; import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
import { useUpdateAnyRequest } from '../hooks/useUpdateAnyRequest'; import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
import { useUpdateRequest } from '../hooks/useUpdateRequest'; import { useUpdateHttpRequest } from '../hooks/useUpdateHttpRequest';
import { fallbackRequestName } from '../lib/fallbackRequestName'; import { fallbackRequestName } from '../lib/fallbackRequestName';
import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore'; import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
import type { Folder, HttpRequest, Workspace } from '../lib/models'; import type { Folder, GrpcRequest, HttpRequest, Workspace } from '../lib/models';
import { isResponseLoading } from '../lib/models'; import { isResponseLoading } from '../lib/models';
import { ContextMenu } from './core/Dropdown'; import { ContextMenu } from './core/Dropdown';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
@@ -48,7 +49,7 @@ enum ItemTypes {
} }
interface TreeNode { interface TreeNode {
item: Workspace | Folder | HttpRequest; item: Workspace | Folder | HttpRequest | GrpcRequest;
children: TreeNode[]; children: TreeNode[];
depth: number; depth: number;
} }
@@ -58,7 +59,8 @@ export function Sidebar({ className }: Props) {
const sidebarRef = useRef<HTMLLIElement>(null); const sidebarRef = useRef<HTMLLIElement>(null);
const activeRequestId = useActiveRequestId(); const activeRequestId = useActiveRequestId();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const requests = useRequests(); const httpRequests = useHttpRequests();
const grpcRequests = useGrpcRequests();
const folders = useFolders(); const folders = useFolders();
const deleteAnyRequest = useDeleteAnyRequest(); const deleteAnyRequest = useDeleteAnyRequest();
const activeWorkspace = useActiveWorkspace(); const activeWorkspace = useActiveWorkspace();
@@ -67,7 +69,7 @@ export function Sidebar({ className }: Props) {
const [hasFocus, setHasFocus] = useState<boolean>(false); const [hasFocus, setHasFocus] = useState<boolean>(false);
const [selectedId, setSelectedId] = useState<string | null>(null); const [selectedId, setSelectedId] = useState<string | null>(null);
const [selectedTree, setSelectedTree] = useState<TreeNode | null>(null); const [selectedTree, setSelectedTree] = useState<TreeNode | null>(null);
const updateAnyRequest = useUpdateAnyRequest(); const updateAnyRequest = useUpdateAnyHttpRequest();
const updateAnyFolder = useUpdateAnyFolder(); const updateAnyFolder = useUpdateAnyFolder();
const [draggingId, setDraggingId] = useState<string | null>(null); const [draggingId, setDraggingId] = useState<string | null>(null);
const [hoveredTree, setHoveredTree] = useState<TreeNode | null>(null); const [hoveredTree, setHoveredTree] = useState<TreeNode | null>(null);
@@ -78,7 +80,7 @@ export function Sidebar({ className }: Props) {
namespace: NAMESPACE_NO_SYNC, namespace: NAMESPACE_NO_SYNC,
}); });
useHotKey('request.duplicate', () => { useHotKey('http_request.duplicate', () => {
duplicateRequest.mutate(); duplicateRequest.mutate();
}); });
@@ -110,7 +112,7 @@ export function Sidebar({ className }: Props) {
// Put requests and folders into a tree structure // Put requests and folders into a tree structure
const next = (node: TreeNode): TreeNode => { const next = (node: TreeNode): TreeNode => {
const childItems = [...requests, ...folders].filter((f) => const childItems = [...httpRequests, ...grpcRequests, ...folders].filter((f) =>
node.item.model === 'workspace' ? f.folderId == null : f.folderId === node.item.id, node.item.model === 'workspace' ? f.folderId == null : f.folderId === node.item.id,
); );
@@ -119,7 +121,7 @@ export function Sidebar({ className }: Props) {
for (const item of childItems) { for (const item of childItems) {
treeParentMap[item.id] = node; treeParentMap[item.id] = node;
node.children.push(next({ item, children: [], depth })); node.children.push(next({ item, children: [], depth }));
if (item.model === 'http_request') { if (item.model !== 'folder') {
selectableRequests.push({ id: item.id, index: selectableRequestIndex++, tree: node }); selectableRequests.push({ id: item.id, index: selectableRequestIndex++, tree: node });
} }
} }
@@ -129,7 +131,7 @@ export function Sidebar({ className }: Props) {
const tree = next({ item: activeWorkspace, children: [], depth: 0 }); const tree = next({ item: activeWorkspace, children: [], depth: 0 });
return { tree, treeParentMap, selectableRequests }; return { tree, treeParentMap, selectableRequests };
}, [activeWorkspace, requests, folders]); }, [activeWorkspace, httpRequests, grpcRequests, folders]);
const focusActiveRequest = useCallback( const focusActiveRequest = useCallback(
( (
@@ -160,7 +162,7 @@ export function Sidebar({ className }: Props) {
); );
const handleSelect = useCallback( const handleSelect = useCallback(
(id: string) => { async (id: string) => {
const tree = treeParentMap[id ?? 'n/a'] ?? null; const tree = treeParentMap[id ?? 'n/a'] ?? null;
const children = tree?.children ?? []; const children = tree?.children ?? [];
const node = children.find((m) => m.item.id === id) ?? null; const node = children.find((m) => m.item.id === id) ?? null;
@@ -171,7 +173,7 @@ export function Sidebar({ className }: Props) {
const { item } = node; const { item } = node;
if (item.model === 'folder') { if (item.model === 'folder') {
collapsed.set((c) => ({ ...c, [item.id]: !c[item.id] })); await collapsed.set((c) => ({ ...c, [item.id]: !c[item.id] }));
} else { } else {
routes.navigate('request', { routes.navigate('request', {
requestId: id, requestId: id,
@@ -339,6 +341,10 @@ export function Sidebar({ className }: Props) {
if (child.item.model === 'folder') { if (child.item.model === 'folder') {
const updateFolder = (f: Folder) => ({ ...f, sortPriority, folderId }); const updateFolder = (f: Folder) => ({ ...f, sortPriority, folderId });
return updateAnyFolder.mutateAsync({ id: child.item.id, update: updateFolder }); return updateAnyFolder.mutateAsync({ id: child.item.id, update: updateFolder });
} else if (child.item.model === 'grpc_request') {
// TODO
// const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId });
// return updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest });
} else if (child.item.model === 'http_request') { } else if (child.item.model === 'http_request') {
const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId }); const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId });
return updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest }); return updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest });
@@ -350,6 +356,10 @@ export function Sidebar({ className }: Props) {
if (child.item.model === 'folder') { if (child.item.model === 'folder') {
const updateFolder = (f: Folder) => ({ ...f, sortPriority, folderId }); const updateFolder = (f: Folder) => ({ ...f, sortPriority, folderId });
await updateAnyFolder.mutateAsync({ id: child.item.id, update: updateFolder }); await updateAnyFolder.mutateAsync({ id: child.item.id, update: updateFolder });
} else if (child.item.model === 'grpc_request') {
// TODO
// const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId });
// await updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest });
} else if (child.item.model === 'http_request') { } else if (child.item.model === 'http_request') {
const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId }); const updateRequest = (r: HttpRequest) => ({ ...r, sortPriority, folderId });
await updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest }); await updateAnyRequest.mutateAsync({ id: child.item.id, update: updateRequest });
@@ -454,7 +464,9 @@ function SidebarItems({
itemId={child.item.id} itemId={child.item.id}
itemName={child.item.name} itemName={child.item.name}
itemFallbackName={ itemFallbackName={
child.item.model === 'http_request' ? fallbackRequestName(child.item) : 'New Folder' child.item.model === 'http_request' || child.item.model === 'grpc_request'
? fallbackRequestName(child.item)
: 'New Folder'
} }
itemModel={child.item.model} itemModel={child.item.model}
onMove={handleMove} onMove={handleMove}
@@ -524,16 +536,15 @@ const SidebarItem = forwardRef(function SidebarItem(
ref: ForwardedRef<HTMLLIElement>, ref: ForwardedRef<HTMLLIElement>,
) { ) {
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest();
const createRequest = useCreateRequest(); const createRequest = useCreateHttpRequest();
const createFolder = useCreateFolder(); const createFolder = useCreateFolder();
const deleteFolder = useDeleteFolder(itemId); const deleteFolder = useDeleteFolder(itemId);
const deleteRequest = useDeleteRequest(itemId); const deleteRequest = useDeleteRequest(itemId);
const duplicateRequest = useDuplicateRequest({ id: itemId, navigateAfter: true }); const duplicateRequest = useDuplicateRequest({ id: itemId, navigateAfter: true });
const sendRequest = useSendRequest(itemId); const sendRequest = useSendRequest(itemId);
const sendAndDownloadRequest = useSendRequest(itemId, { download: true });
const sendManyRequests = useSendManyRequests(); const sendManyRequests = useSendManyRequests();
const latestResponse = useLatestResponse(itemId); const latestResponse = useLatestResponse(itemId);
const updateRequest = useUpdateRequest(itemId); const updateRequest = useUpdateHttpRequest(itemId);
const updateAnyFolder = useUpdateAnyFolder(); const updateAnyFolder = useUpdateAnyFolder();
const prompt = usePrompt(); const prompt = usePrompt();
const [editing, setEditing] = useState<boolean>(false); const [editing, setEditing] = useState<boolean>(false);
@@ -570,7 +581,7 @@ const SidebarItem = forwardRef(function SidebarItem(
); );
const handleStartEditing = useCallback(() => { const handleStartEditing = useCallback(() => {
if (itemModel !== 'http_request') return; if (itemModel !== 'http_request' && itemModel !== 'grpc_request') return;
setEditing(true); setEditing(true);
}, [setEditing, itemModel]); }, [setEditing, itemModel]);
@@ -652,7 +663,7 @@ const SidebarItem = forwardRef(function SidebarItem(
{ {
key: 'sendRequest', key: 'sendRequest',
label: 'Send', label: 'Send',
hotKeyAction: 'request.send', hotKeyAction: 'http_request.send',
hotKeyLabelOnly: true, // Already bound in URL bar hotKeyLabelOnly: true, // Already bound in URL bar
leftSlot: <Icon icon="sendHorizontal" />, leftSlot: <Icon icon="sendHorizontal" />,
onSelect: () => sendRequest.mutate(), onSelect: () => sendRequest.mutate(),
@@ -661,7 +672,7 @@ const SidebarItem = forwardRef(function SidebarItem(
{ {
key: 'duplicateRequest', key: 'duplicateRequest',
label: 'Duplicate', label: 'Duplicate',
hotKeyAction: 'request.duplicate', hotKeyAction: 'http_request.duplicate',
hotKeyLabelOnly: true, // Would trigger for every request (bad) hotKeyLabelOnly: true, // Would trigger for every request (bad)
leftSlot: <Icon icon="copy" />, leftSlot: <Icon icon="copy" />,
onSelect: () => { onSelect: () => {

View File

@@ -1,6 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import { useCreateFolder } from '../hooks/useCreateFolder'; import { useCreateFolder } from '../hooks/useCreateFolder';
import { useCreateRequest } from '../hooks/useCreateRequest'; import { useCreateGrpcRequest } from '../hooks/useCreateGrpcRequest';
import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
import { useSidebarHidden } from '../hooks/useSidebarHidden'; import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { trackEvent } from '../lib/analytics'; import { trackEvent } from '../lib/analytics';
import { Dropdown } from './core/Dropdown'; import { Dropdown } from './core/Dropdown';
@@ -8,16 +9,17 @@ import { IconButton } from './core/IconButton';
import { HStack } from './core/Stacks'; import { HStack } from './core/Stacks';
export const SidebarActions = memo(function SidebarActions() { export const SidebarActions = memo(function SidebarActions() {
const createRequest = useCreateRequest(); const createHttpRequest = useCreateHttpRequest();
const createGrpcRequest = useCreateGrpcRequest();
const createFolder = useCreateFolder(); const createFolder = useCreateFolder();
const { hidden, toggle } = useSidebarHidden(); const { hidden, toggle } = useSidebarHidden();
return ( return (
<HStack> <HStack>
<IconButton <IconButton
onClick={() => { onClick={async () => {
trackEvent('Sidebar', 'Toggle'); trackEvent('Sidebar', 'Toggle');
toggle(); await toggle();
}} }}
className="pointer-events-auto" className="pointer-events-auto"
size="sm" size="sm"
@@ -28,14 +30,19 @@ export const SidebarActions = memo(function SidebarActions() {
<Dropdown <Dropdown
items={[ items={[
{ {
key: 'create-request', key: 'create-http-request',
label: 'New Request', label: 'HTTP Request',
hotKeyAction: 'request.create', hotKeyAction: 'http_request.create',
onSelect: () => createRequest.mutate({}), onSelect: () => createHttpRequest.mutate({}),
},
{
key: 'create-grpc-request',
label: 'GRPC Request',
onSelect: () => createGrpcRequest.mutate({}),
}, },
{ {
key: 'create-folder', key: 'create-folder',
label: 'New Folder', label: 'Folder',
onSelect: () => createFolder.mutate({}), onSelect: () => createFolder.mutate({}),
}, },
]} ]}

View File

@@ -83,7 +83,7 @@ export const UrlBar = memo(function UrlBar({
className="w-8 mr-0.5 my-0.5" className="w-8 mr-0.5 my-0.5"
icon={isLoading ? 'update' : submitIcon} icon={isLoading ? 'update' : submitIcon}
spin={isLoading} spin={isLoading}
hotkeyAction="request.send" hotkeyAction="http_request.send"
/> />
) )
} }

View File

@@ -34,6 +34,7 @@ export default function Workspace() {
const { setWidth, width, resetWidth } = useSidebarWidth(); const { setWidth, width, resetWidth } = useSidebarWidth();
const { hide, show, hidden } = useSidebarHidden(); const { hide, show, hidden } = useSidebarHidden();
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest();
console.log('ACTIVE REQUEST', activeRequest);
const windowSize = useWindowSize(); const windowSize = useWindowSize();
const [floating, setFloating] = useState<boolean>(false); const [floating, setFloating] = useState<boolean>(false);
@@ -166,7 +167,7 @@ export default function Workspace() {
> >
<WorkspaceHeader className="pointer-events-none" /> <WorkspaceHeader className="pointer-events-none" />
</HeaderSize> </HeaderSize>
{activeRequest?.name.includes('gRPC') ? ( {activeRequest?.model === 'grpc_request' ? (
<GrpcConnectionLayout style={body} /> <GrpcConnectionLayout style={body} />
) : ( ) : (
<HttpRequestLayout style={body} /> <HttpRequestLayout style={body} />

View File

@@ -140,7 +140,7 @@ export function SplitLayout({
const activeRequestId = useActiveRequestId(); const activeRequestId = useActiveRequestId();
if (activeRequestId === null) { if (activeRequestId === null) {
return <HotKeyList hotkeys={['request.create', 'sidebar.toggle']} />; return <HotKeyList hotkeys={['http_request.create', 'sidebar.toggle']} />;
} }
return ( return (

View File

@@ -1,9 +1,28 @@
import type { HttpRequest } from '../lib/models'; import { r } from 'vitest/dist/types-94cfe4b4';
import type { GrpcRequest, HttpRequest } from '../lib/models';
import { useActiveRequestId } from './useActiveRequestId'; import { useActiveRequestId } from './useActiveRequestId';
import { useRequests } from './useRequests'; import { useGrpcRequests } from './useGrpcRequests';
import { useHttpRequests } from './useHttpRequests';
export function useActiveRequest(): HttpRequest | null { interface TypeMap {
const requestId = useActiveRequestId(); http_request: HttpRequest;
const requests = useRequests(); grpc_request: GrpcRequest;
return requests.find((r) => r.id === requestId) ?? null; }
export function useActiveRequest<T extends keyof TypeMap>(
model?: T | undefined,
): TypeMap[T] | null {
const requestId = useActiveRequestId();
const httpRequests = useHttpRequests();
const grpcRequests = useGrpcRequests();
if (model === 'http_request') {
return (httpRequests.find((r) => r.id === requestId) ?? null) as TypeMap[T] | null;
} else if (model === 'grpc_request') {
return (grpcRequests.find((r) => r.id === requestId) ?? null) as TypeMap[T] | null;
} else {
return (grpcRequests.find((r) => r.id === requestId) ??
httpRequests.find((r) => r.id === requestId) ??
null) as TypeMap[T] | null;
}
} }

View File

@@ -0,0 +1,55 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import { trackEvent } from '../lib/analytics';
import type { GrpcRequest, HttpRequest } from '../lib/models';
import { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveRequest } from './useActiveRequest';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes';
import { grpcRequestsQueryKey } from './useGrpcRequests';
import { httpRequestsQueryKey } from './useHttpRequests';
export function useCreateGrpcRequest() {
const workspaceId = useActiveWorkspaceId();
const activeEnvironmentId = useActiveEnvironmentId();
// const activeRequest = useActiveRequest();
const activeRequest = null;
const routes = useAppRoutes();
const queryClient = useQueryClient();
return useMutation<
GrpcRequest,
unknown,
Partial<Pick<GrpcRequest, 'name' | 'sortPriority' | 'folderId'>>
>({
mutationFn: (patch) => {
if (workspaceId === null) {
throw new Error("Cannot create grpc request when there's no active workspace");
}
if (patch.sortPriority === undefined) {
if (activeRequest != null) {
// Place above currently-active request
// patch.sortPriority = activeRequest.sortPriority + 0.0001;
} else {
// Place at the very top
patch.sortPriority = -Date.now();
}
}
// patch.folderId = patch.folderId; // TODO: || activeRequest?.folderId;
return invoke('cmd_create_grpc_request', { workspaceId, name: '', ...patch });
},
onSettled: () => trackEvent('GrpcRequest', 'Create'),
onSuccess: async (request) => {
queryClient.setQueryData<GrpcRequest[]>(
grpcRequestsQueryKey({ workspaceId: request.workspaceId }),
(requests) => [...(requests ?? []), request],
);
// TODO: This should navigate to the new request
routes.navigate('request', {
workspaceId: request.workspaceId,
requestId: request.id,
environmentId: activeEnvironmentId ?? undefined,
});
},
});
}

View File

@@ -6,9 +6,9 @@ import { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveRequest } from './useActiveRequest'; import { useActiveRequest } from './useActiveRequest';
import { useActiveWorkspaceId } from './useActiveWorkspaceId'; import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes'; import { useAppRoutes } from './useAppRoutes';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
export function useCreateRequest() { export function useCreateHttpRequest() {
const workspaceId = useActiveWorkspaceId(); const workspaceId = useActiveWorkspaceId();
const activeEnvironmentId = useActiveEnvironmentId(); const activeEnvironmentId = useActiveEnvironmentId();
const activeRequest = useActiveRequest(); const activeRequest = useActiveRequest();
@@ -34,12 +34,12 @@ export function useCreateRequest() {
} }
} }
patch.folderId = patch.folderId || activeRequest?.folderId; patch.folderId = patch.folderId || activeRequest?.folderId;
return invoke('cmd_create_request', { workspaceId, name: '', ...patch }); return invoke('cmd_create_http_request', { workspaceId, name: '', ...patch });
}, },
onSettled: () => trackEvent('HttpRequest', 'Create'), onSettled: () => trackEvent('HttpRequest', 'Create'),
onSuccess: async (request) => { onSuccess: async (request) => {
queryClient.setQueryData<HttpRequest[]>( queryClient.setQueryData<HttpRequest[]>(
requestsQueryKey({ workspaceId: request.workspaceId }), httpRequestsQueryKey({ workspaceId: request.workspaceId }),
(requests) => [...(requests ?? []), request], (requests) => [...(requests ?? []), request],
); );
routes.navigate('request', { routes.navigate('request', {

View File

@@ -6,7 +6,7 @@ import { fallbackRequestName } from '../lib/fallbackRequestName';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { getRequest } from '../lib/store'; import { getRequest } from '../lib/store';
import { useConfirm } from './useConfirm'; import { useConfirm } from './useConfirm';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
import { responsesQueryKey } from './useResponses'; import { responsesQueryKey } from './useResponses';
export function useDeleteAnyRequest() { export function useDeleteAnyRequest() {
@@ -27,7 +27,7 @@ export function useDeleteAnyRequest() {
), ),
}); });
if (!confirmed) return null; if (!confirmed) return null;
return invoke('cmd_delete_request', { requestId: id }); return invoke('cmd_delete_http_request', { requestId: id });
}, },
onSettled: () => trackEvent('HttpRequest', 'Delete'), onSettled: () => trackEvent('HttpRequest', 'Delete'),
onSuccess: async (request) => { onSuccess: async (request) => {
@@ -36,7 +36,7 @@ export function useDeleteAnyRequest() {
const { workspaceId, id: requestId } = request; const { workspaceId, id: requestId } = request;
queryClient.setQueryData(responsesQueryKey({ requestId }), []); // Responses were deleted queryClient.setQueryData(responsesQueryKey({ requestId }), []); // Responses were deleted
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey({ workspaceId }), (requests) => queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey({ workspaceId }), (requests) =>
(requests ?? []).filter((r) => r.id !== requestId), (requests ?? []).filter((r) => r.id !== requestId),
); );
}, },

View File

@@ -6,7 +6,7 @@ import type { Folder } from '../lib/models';
import { getFolder } from '../lib/store'; import { getFolder } from '../lib/store';
import { useConfirm } from './useConfirm'; import { useConfirm } from './useConfirm';
import { foldersQueryKey } from './useFolders'; import { foldersQueryKey } from './useFolders';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
export function useDeleteFolder(id: string | null) { export function useDeleteFolder(id: string | null) {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@@ -36,7 +36,7 @@ export function useDeleteFolder(id: string | null) {
const { workspaceId } = folder; const { workspaceId } = folder;
// Nesting makes it hard to clean things up, so just clear everything that could have been deleted // Nesting makes it hard to clean things up, so just clear everything that could have been deleted
await queryClient.invalidateQueries(requestsQueryKey({ workspaceId })); await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
await queryClient.invalidateQueries(foldersQueryKey({ workspaceId })); await queryClient.invalidateQueries(foldersQueryKey({ workspaceId }));
}, },
}); });

View File

@@ -6,7 +6,7 @@ import type { Workspace } from '../lib/models';
import { useActiveWorkspaceId } from './useActiveWorkspaceId'; import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes'; import { useAppRoutes } from './useAppRoutes';
import { useConfirm } from './useConfirm'; import { useConfirm } from './useConfirm';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
import { workspacesQueryKey } from './useWorkspaces'; import { workspacesQueryKey } from './useWorkspaces';
export function useDeleteWorkspace(workspace: Workspace | null) { export function useDeleteWorkspace(workspace: Workspace | null) {
@@ -43,8 +43,8 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
} }
// Also clean up other things that may have been deleted // Also clean up other things that may have been deleted
queryClient.setQueryData(requestsQueryKey({ workspaceId }), []); queryClient.setQueryData(httpRequestsQueryKey({ workspaceId }), []);
await queryClient.invalidateQueries(requestsQueryKey({ workspaceId })); await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
}, },
}); });
} }

View File

@@ -5,7 +5,7 @@ import type { HttpRequest } from '../lib/models';
import { useActiveEnvironmentId } from './useActiveEnvironmentId'; import { useActiveEnvironmentId } from './useActiveEnvironmentId';
import { useActiveWorkspaceId } from './useActiveWorkspaceId'; import { useActiveWorkspaceId } from './useActiveWorkspaceId';
import { useAppRoutes } from './useAppRoutes'; import { useAppRoutes } from './useAppRoutes';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
export function useDuplicateRequest({ export function useDuplicateRequest({
id, id,
@@ -21,12 +21,12 @@ export function useDuplicateRequest({
return useMutation<HttpRequest, string>({ return useMutation<HttpRequest, string>({
mutationFn: async () => { mutationFn: async () => {
if (id === null) throw new Error("Can't duplicate a null request"); if (id === null) throw new Error("Can't duplicate a null request");
return invoke('cmd_duplicate_request', { id }); return invoke('cmd_duplicate_http_request', { id });
}, },
onSettled: () => trackEvent('HttpRequest', 'Duplicate'), onSettled: () => trackEvent('HttpRequest', 'Duplicate'),
onSuccess: async (request) => { onSuccess: async (request) => {
queryClient.setQueryData<HttpRequest[]>( queryClient.setQueryData<HttpRequest[]>(
requestsQueryKey({ workspaceId: request.workspaceId }), httpRequestsQueryKey({ workspaceId: request.workspaceId }),
(requests) => [...(requests ?? []), request], (requests) => [...(requests ?? []), request],
); );
if (navigateAfter && activeWorkspaceId !== null) { if (navigateAfter && activeWorkspaceId !== null) {

View File

@@ -0,0 +1,22 @@
import { useQuery } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import type { GrpcRequest } from '../lib/models';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
export function grpcRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
return ['grpc_requests', { workspaceId }];
}
export function useGrpcRequests() {
const workspaceId = useActiveWorkspaceId();
return (
useQuery({
enabled: workspaceId != null,
queryKey: grpcRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
queryFn: async () => {
if (workspaceId == null) return [];
return (await invoke('cmd_list_grpc_requests', { workspaceId })) as GrpcRequest[];
},
}).data ?? []
);
}

View File

@@ -6,11 +6,11 @@ import { useOsInfo } from './useOsInfo';
export type HotkeyAction = export type HotkeyAction =
| 'environmentEditor.toggle' | 'environmentEditor.toggle'
| 'grpc.send'
| 'hotkeys.showHelp' | 'hotkeys.showHelp'
| 'request.create' | 'grpc_request.send'
| 'request.duplicate' | 'http_request.create'
| 'request.send' | 'http_request.duplicate'
| 'http_request.send'
| 'requestSwitcher.next' | 'requestSwitcher.next'
| 'requestSwitcher.prev' | 'requestSwitcher.prev'
| 'settings.show' | 'settings.show'
@@ -20,11 +20,11 @@ export type HotkeyAction =
const hotkeys: Record<HotkeyAction, string[]> = { const hotkeys: Record<HotkeyAction, string[]> = {
'environmentEditor.toggle': ['CmdCtrl+Shift+e'], 'environmentEditor.toggle': ['CmdCtrl+Shift+e'],
'grpc.send': ['CmdCtrl+Enter', 'CmdCtrl+r'], 'grpc_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'],
'hotkeys.showHelp': ['CmdCtrl+Shift+/'], 'hotkeys.showHelp': ['CmdCtrl+Shift+/'],
'request.create': ['CmdCtrl+n'], 'http_request.create': ['CmdCtrl+n'],
'request.duplicate': ['CmdCtrl+d'], 'http_request.duplicate': ['CmdCtrl+d'],
'request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'], 'http_request.send': ['CmdCtrl+Enter', 'CmdCtrl+r'],
'requestSwitcher.next': ['Control+Shift+Tab'], 'requestSwitcher.next': ['Control+Shift+Tab'],
'requestSwitcher.prev': ['Control+Tab'], 'requestSwitcher.prev': ['Control+Tab'],
'settings.show': ['CmdCtrl+,'], 'settings.show': ['CmdCtrl+,'],
@@ -35,11 +35,11 @@ const hotkeys: Record<HotkeyAction, string[]> = {
const hotkeyLabels: Record<HotkeyAction, string> = { const hotkeyLabels: Record<HotkeyAction, string> = {
'environmentEditor.toggle': 'Edit Environments', 'environmentEditor.toggle': 'Edit Environments',
'grpc.send': 'Send Message', 'grpc_request.send': 'Send Message',
'hotkeys.showHelp': 'Show Keyboard Shortcuts', 'hotkeys.showHelp': 'Show Keyboard Shortcuts',
'request.create': 'New Request', 'http_request.create': 'New Request',
'request.duplicate': 'Duplicate Request', 'http_request.duplicate': 'Duplicate Request',
'request.send': 'Send Request', 'http_request.send': 'Send Request',
'requestSwitcher.next': 'Go To Previous Request', 'requestSwitcher.next': 'Go To Previous Request',
'requestSwitcher.prev': 'Go To Next Request', 'requestSwitcher.prev': 'Go To Next Request',
'settings.show': 'Open Settings', 'settings.show': 'Open Settings',

View File

@@ -3,19 +3,19 @@ import { invoke } from '@tauri-apps/api';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { useActiveWorkspaceId } from './useActiveWorkspaceId'; import { useActiveWorkspaceId } from './useActiveWorkspaceId';
export function requestsQueryKey({ workspaceId }: { workspaceId: string }) { export function httpRequestsQueryKey({ workspaceId }: { workspaceId: string }) {
return ['http_requests', { workspaceId }]; return ['http_requests', { workspaceId }];
} }
export function useRequests() { export function useHttpRequests() {
const workspaceId = useActiveWorkspaceId(); const workspaceId = useActiveWorkspaceId();
return ( return (
useQuery({ useQuery({
enabled: workspaceId != null, enabled: workspaceId != null,
queryKey: requestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }), queryKey: httpRequestsQueryKey({ workspaceId: workspaceId ?? 'n/a' }),
queryFn: async () => { queryFn: async () => {
if (workspaceId == null) return []; if (workspaceId == null) return [];
return (await invoke('cmd_list_requests', { workspaceId })) as HttpRequest[]; return (await invoke('cmd_list_http_requests', { workspaceId })) as HttpRequest[];
}, },
}).data ?? [] }).data ?? []
); );

View File

@@ -1,7 +1,7 @@
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { useRequests } from './useRequests'; import { useHttpRequests } from './useHttpRequests';
export function useRequest(id: string | null): HttpRequest | null { export function useRequest(id: string | null): HttpRequest | null {
const requests = useRequests(); const requests = useHttpRequests();
return requests.find((r) => r.id === id) ?? null; return requests.find((r) => r.id === id) ?? null;
} }

View File

@@ -2,9 +2,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { getRequest } from '../lib/store'; import { getRequest } from '../lib/store';
import { requestsQueryKey } from './useRequests'; import { httpRequestsQueryKey } from './useHttpRequests';
export function useUpdateAnyRequest() { export function useUpdateAnyHttpRequest() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation< return useMutation<
@@ -20,14 +20,14 @@ export function useUpdateAnyRequest() {
const patchedRequest = const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update }; typeof update === 'function' ? update(request) : { ...request, ...update };
await invoke('cmd_update_request', { request: patchedRequest }); await invoke('cmd_update_http_request', { request: patchedRequest });
}, },
onMutate: async ({ id, update }) => { onMutate: async ({ id, update }) => {
const request = await getRequest(id); const request = await getRequest(id);
if (request === null) return; if (request === null) return;
const patchedRequest = const patchedRequest =
typeof update === 'function' ? update(request) : { ...request, ...update }; typeof update === 'function' ? update(request) : { ...request, ...update };
queryClient.setQueryData<HttpRequest[]>(requestsQueryKey(request), (requests) => queryClient.setQueryData<HttpRequest[]>(httpRequestsQueryKey(request), (requests) =>
(requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)), (requests ?? []).map((r) => (r.id === patchedRequest.id ? patchedRequest : r)),
); );
}, },

View File

@@ -1,9 +1,9 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '../lib/models'; import type { HttpRequest } from '../lib/models';
import { useUpdateAnyRequest } from './useUpdateAnyRequest'; import { useUpdateAnyHttpRequest } from './useUpdateAnyHttpRequest';
export function useUpdateRequest(id: string | null) { export function useUpdateHttpRequest(id: string | null) {
const updateAnyRequest = useUpdateAnyRequest(); const updateAnyRequest = useUpdateAnyHttpRequest();
return useMutation<void, unknown, Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest)>({ return useMutation<void, unknown, Partial<HttpRequest> | ((r: HttpRequest) => HttpRequest)>({
mutationFn: async (update) => updateAnyRequest.mutateAsync({ id: id ?? 'n/a', update }), mutationFn: async (update) => updateAnyRequest.mutateAsync({ id: id ?? 'n/a', update }),
}); });

View File

@@ -9,6 +9,7 @@ export function trackEvent(
| 'Workspace' | 'Workspace'
| 'Environment' | 'Environment'
| 'Folder' | 'Folder'
| 'GrpcRequest'
| 'HttpRequest' | 'HttpRequest'
| 'HttpResponse' | 'HttpResponse'
| 'KeyValue', | 'KeyValue',

View File

@@ -1,6 +1,6 @@
import type { HttpRequest } from './models'; import type { GrpcRequest, HttpRequest } from './models';
export function fallbackRequestName(r: HttpRequest | null): string { export function fallbackRequestName(r: HttpRequest | GrpcRequest | null): string {
if (r == null) return ''; if (r == null) return '';
if (r.name) { if (r.name) {
@@ -9,7 +9,7 @@ export function fallbackRequestName(r: HttpRequest | null): string {
const withoutVariables = r.url.replace(/\$\{\[[^\]]+]}/g, ''); const withoutVariables = r.url.replace(/\$\{\[[^\]]+]}/g, '');
if (withoutVariables.trim() === '') { if (withoutVariables.trim() === '') {
return 'New Request'; return r.model === 'http_request' ? 'New HTTP Request' : 'new gRPC Request';
} }
const fixedUrl = r.url.match(/^https?:\/\//) ? r.url : 'http://' + r.url; const fixedUrl = r.url.match(/^https?:\/\//) ? r.url : 'http://' + r.url;

View File

@@ -12,6 +12,7 @@ export const AUTH_TYPE_BEARER = 'bearer';
export type Model = export type Model =
| Settings | Settings
| Workspace | Workspace
| GrpcRequest
| HttpRequest | HttpRequest
| HttpResponse | HttpResponse
| KeyValue | KeyValue
@@ -101,6 +102,18 @@ export interface HttpUrlParameter {
enabled?: boolean; enabled?: boolean;
} }
export interface GrpcRequest extends BaseModel {
readonly workspaceId: string;
readonly model: 'grpc_request';
folderId: string | null;
sortPriority: number;
name: string;
url: string;
service: string | null;
method: string | null;
message: string;
}
export interface HttpRequest extends BaseModel { export interface HttpRequest extends BaseModel {
readonly workspaceId: string; readonly workspaceId: string;
readonly model: 'http_request'; readonly model: 'http_request';

View File

@@ -7,7 +7,7 @@ export async function getSettings(): Promise<Settings> {
export async function getRequest(id: string | null): Promise<HttpRequest | null> { export async function getRequest(id: string | null): Promise<HttpRequest | null> {
if (id === null) return null; if (id === null) return null;
const request: HttpRequest = (await invoke('cmd_get_request', { id })) ?? null; const request: HttpRequest = (await invoke('cmd_get_http_request', { id })) ?? null;
if (request == null) { if (request == null) {
return null; return null;
} }