mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-22 08:38:29 +02:00
Working sidebar actions for grpc
This commit is contained in:
@@ -24,7 +24,6 @@ use tonic_reflection::pb::server_reflection_response::MessageResponse;
|
|||||||
use tonic_reflection::pb::ServerReflectionRequest;
|
use tonic_reflection::pb::ServerReflectionRequest;
|
||||||
|
|
||||||
pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool, String> {
|
pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool, String> {
|
||||||
println!("FILL POOL FROM FILES");
|
|
||||||
let mut pool = DescriptorPool::new();
|
let mut pool = DescriptorPool::new();
|
||||||
let random_file_name = format!("{}.desc", uuid::Uuid::new_v4());
|
let random_file_name = format!("{}.desc", uuid::Uuid::new_v4());
|
||||||
let desc_path = temp_dir().join(random_file_name);
|
let desc_path = temp_dir().join(random_file_name);
|
||||||
@@ -51,8 +50,6 @@ pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Running: {:?}", cmd);
|
|
||||||
|
|
||||||
let output = cmd.output().map_err(|e| e.to_string())?;
|
let output = cmd.output().map_err(|e| e.to_string())?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -75,21 +72,7 @@ pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool,
|
|||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_transport() -> Client<HttpsConnector<HttpConnector>, BoxBody> {
|
|
||||||
let connector = HttpsConnectorBuilder::new().with_native_roots();
|
|
||||||
let connector = connector.https_or_http().enable_http2().wrap_connector({
|
|
||||||
let mut http_connector = HttpConnector::new();
|
|
||||||
http_connector.enforce_http(false);
|
|
||||||
http_connector
|
|
||||||
});
|
|
||||||
Client::builder()
|
|
||||||
.pool_max_idle_per_host(0)
|
|
||||||
.http2_only(true)
|
|
||||||
.build(connector)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fill_pool(uri: &Uri) -> Result<DescriptorPool, String> {
|
pub async fn fill_pool(uri: &Uri) -> Result<DescriptorPool, String> {
|
||||||
println!("FILL POOL FROM URI");
|
|
||||||
let mut pool = DescriptorPool::new();
|
let mut pool = DescriptorPool::new();
|
||||||
let mut client = ServerReflectionClient::with_origin(get_transport(), uri.clone());
|
let mut client = ServerReflectionClient::with_origin(get_transport(), uri.clone());
|
||||||
|
|
||||||
@@ -103,6 +86,19 @@ pub async fn fill_pool(uri: &Uri) -> Result<DescriptorPool, String> {
|
|||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_transport() -> Client<HttpsConnector<HttpConnector>, BoxBody> {
|
||||||
|
let connector = HttpsConnectorBuilder::new().with_native_roots();
|
||||||
|
let connector = connector.https_or_http().enable_http2().wrap_connector({
|
||||||
|
let mut http_connector = HttpConnector::new();
|
||||||
|
http_connector.enforce_http(false);
|
||||||
|
http_connector
|
||||||
|
});
|
||||||
|
Client::builder()
|
||||||
|
.pool_max_idle_per_host(0)
|
||||||
|
.http2_only(true)
|
||||||
|
.build(connector)
|
||||||
|
}
|
||||||
|
|
||||||
async fn list_services(
|
async fn list_services(
|
||||||
reflect_client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
|
reflect_client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
|
||||||
) -> Result<Vec<String>, String> {
|
) -> Result<Vec<String>, String> {
|
||||||
|
|||||||
@@ -44,16 +44,17 @@ use crate::http::send_http_request;
|
|||||||
use crate::models::{
|
use crate::models::{
|
||||||
cancel_pending_grpc_connections, cancel_pending_responses, create_response,
|
cancel_pending_grpc_connections, cancel_pending_responses, create_response,
|
||||||
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
||||||
delete_folder, delete_grpc_connection, delete_http_request, delete_http_response,
|
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
|
||||||
delete_workspace, duplicate_grpc_request, duplicate_http_request, get_cookie_jar,
|
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
|
||||||
get_environment, get_folder, get_grpc_request, get_http_request, get_http_response,
|
get_cookie_jar, get_environment, get_folder, get_grpc_request, get_http_request,
|
||||||
get_key_value_raw, get_or_create_settings, get_workspace, get_workspace_export_resources,
|
get_http_response, get_key_value_raw, get_or_create_settings, get_workspace,
|
||||||
list_cookie_jars, list_environments, list_folders, list_grpc_connections, list_grpc_messages,
|
get_workspace_export_resources, list_cookie_jars, list_environments, list_folders,
|
||||||
list_grpc_requests, list_requests, list_responses, list_workspaces, set_key_value_raw,
|
list_grpc_connections, list_grpc_messages, list_grpc_requests, list_requests, list_responses,
|
||||||
update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment, upsert_folder,
|
list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar,
|
||||||
upsert_grpc_connection, upsert_grpc_message, upsert_grpc_request, upsert_http_request,
|
upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_message,
|
||||||
upsert_workspace, CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection,
|
upsert_grpc_request, upsert_http_request, upsert_workspace, CookieJar, Environment,
|
||||||
GrpcMessage, GrpcRequest, HttpRequest, HttpResponse, KeyValue, Settings, Workspace,
|
EnvironmentVariable, Folder, GrpcConnection, GrpcMessage, 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};
|
||||||
@@ -103,7 +104,6 @@ async fn cmd_grpc_reflect(
|
|||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let uri = safe_uri(&req.url).map_err(|e| e.to_string())?;
|
let uri = safe_uri(&req.url).map_err(|e| e.to_string())?;
|
||||||
if req.proto_files.0.len() > 0 {
|
if req.proto_files.0.len() > 0 {
|
||||||
println!("REFLECT FROM FILES");
|
|
||||||
grpc_handle
|
grpc_handle
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
@@ -1331,8 +1331,8 @@ async fn cmd_update_http_request(
|
|||||||
async fn cmd_delete_grpc_request(
|
async fn cmd_delete_grpc_request(
|
||||||
app_handle: AppHandle,
|
app_handle: AppHandle,
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
) -> Result<HttpRequest, String> {
|
) -> Result<GrpcRequest, String> {
|
||||||
delete_http_request(&app_handle, request_id)
|
delete_grpc_request(&app_handle, request_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1379,6 +1379,26 @@ pub async fn list_responses_by_workspace_id(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_grpc_request(
|
||||||
|
app_handle: &AppHandle,
|
||||||
|
id: &str,
|
||||||
|
) -> Result<GrpcRequest, sqlx::Error> {
|
||||||
|
let req = get_grpc_request(app_handle, id).await?;
|
||||||
|
|
||||||
|
let db = get_db(app_handle).await;
|
||||||
|
let _ = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
DELETE FROM grpc_requests
|
||||||
|
WHERE id = ?
|
||||||
|
"#,
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
.execute(&db)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
emit_deleted_model(app_handle, req)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_grpc_connection(
|
pub async fn delete_grpc_connection(
|
||||||
app_handle: &AppHandle,
|
app_handle: &AppHandle,
|
||||||
id: &str,
|
id: &str,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
|||||||
<div className="overflow-y-auto h-full">
|
<div className="overflow-y-auto h-full">
|
||||||
{...messages.map((m) => (
|
{...messages.map((m) => (
|
||||||
<HStack
|
<HStack
|
||||||
|
role="button"
|
||||||
key={m.id}
|
key={m.id}
|
||||||
space={2}
|
space={2}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -72,7 +73,10 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
|||||||
else setActiveMessageId(m.id);
|
else setActiveMessageId(m.id);
|
||||||
}}
|
}}
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
className={classNames('px-2 py-1 font-mono', m === activeMessage && 'bg-highlight')}
|
className={classNames(
|
||||||
|
'px-2 py-1 font-mono cursor-default group',
|
||||||
|
m === activeMessage && '!bg-highlight',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
className={
|
className={
|
||||||
@@ -80,8 +84,22 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
|
|||||||
}
|
}
|
||||||
icon={m.isInfo ? 'info' : m.isServer ? 'arrowBigDownDash' : 'arrowBigUpDash'}
|
icon={m.isInfo ? 'info' : m.isServer ? 'arrowBigDownDash' : 'arrowBigUpDash'}
|
||||||
/>
|
/>
|
||||||
<div className="w-full truncate text-gray-800 text-2xs">{m.message}</div>
|
<div
|
||||||
<div className="text-gray-600 text-2xs">{format(m.createdAt, 'HH:mm:ss')}</div>
|
className={classNames(
|
||||||
|
'w-full truncate text-gray-800 text-2xs group-hover:text-gray-900',
|
||||||
|
m.id === activeMessageId && 'text-gray-900',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{m.message}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'text-gray-600 text-2xs group-hover:text-gray-700',
|
||||||
|
m.id === activeMessageId && 'text-gray-700',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{format(m.createdAt, 'HH:mm:ss')}
|
||||||
|
</div>
|
||||||
</HStack>
|
</HStack>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ 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 { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
||||||
import { useDeleteAnyRequest } from '../hooks/useDeleteAnyRequest';
|
import { useDeleteAnyGrpcRequest } from '../hooks/useDeleteAnyGrpcRequest';
|
||||||
|
import { useDeleteAnyHttpRequest } from '../hooks/useDeleteAnyHttpRequest';
|
||||||
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
||||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||||
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
||||||
@@ -36,6 +37,7 @@ import { fallbackRequestName } from '../lib/fallbackRequestName';
|
|||||||
import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
|
import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
|
||||||
import type { Folder, GrpcRequest, 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 type { DropdownItem } from './core/Dropdown';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
@@ -65,7 +67,8 @@ export function Sidebar({ className }: Props) {
|
|||||||
const httpRequests = useHttpRequests();
|
const httpRequests = useHttpRequests();
|
||||||
const grpcRequests = useGrpcRequests();
|
const grpcRequests = useGrpcRequests();
|
||||||
const folders = useFolders();
|
const folders = useFolders();
|
||||||
const deleteAnyRequest = useDeleteAnyRequest();
|
const deleteAnyHttpRequest = useDeleteAnyHttpRequest();
|
||||||
|
const deleteAnyGrpcRequest = useDeleteAnyGrpcRequest();
|
||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const duplicateHttpRequest = useDuplicateHttpRequest({
|
const duplicateHttpRequest = useDuplicateHttpRequest({
|
||||||
id: activeRequest?.id ?? null,
|
id: activeRequest?.id ?? null,
|
||||||
@@ -223,9 +226,10 @@ export function Sidebar({ className }: Props) {
|
|||||||
|
|
||||||
const selected = selectableRequests.find((r) => r.id === selectedId);
|
const selected = selectableRequests.find((r) => r.id === selectedId);
|
||||||
if (selected == null) return;
|
if (selected == null) return;
|
||||||
deleteAnyRequest.mutate(selected.id);
|
deleteAnyHttpRequest.mutate(selected.id);
|
||||||
|
deleteAnyGrpcRequest.mutate(selected.id);
|
||||||
},
|
},
|
||||||
[deleteAnyRequest, hasFocus, selectableRequests, selectedId],
|
[deleteAnyHttpRequest, deleteAnyGrpcRequest, hasFocus, selectableRequests, selectedId],
|
||||||
);
|
);
|
||||||
|
|
||||||
useKeyPressEvent('Backspace', handleDeleteKey);
|
useKeyPressEvent('Backspace', handleDeleteKey);
|
||||||
@@ -683,15 +687,19 @@ const SidebarItem = forwardRef(function SidebarItem(
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
...((itemModel === 'http_request'
|
||||||
key: 'sendRequest',
|
? [
|
||||||
label: 'Send',
|
{
|
||||||
hotKeyAction: 'http_request.send',
|
key: 'sendRequest',
|
||||||
hotKeyLabelOnly: true, // Already bound in URL bar
|
label: 'Send',
|
||||||
leftSlot: <Icon icon="sendHorizontal" />,
|
hotKeyAction: 'http_request.send',
|
||||||
onSelect: () => sendRequest.mutate(),
|
hotKeyLabelOnly: true, // Already bound in URL bar
|
||||||
},
|
leftSlot: <Icon icon="sendHorizontal" />,
|
||||||
{ type: 'separator' },
|
onSelect: () => sendRequest.mutate(),
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
]
|
||||||
|
: []) as DropdownItem[]),
|
||||||
{
|
{
|
||||||
key: 'duplicateRequest',
|
key: 'duplicateRequest',
|
||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function Confirm({ onHide, onResult, variant = 'confirm' }: ConfirmProps)
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HStack space={2} justifyContent="end" className="mt-2 mb-4 flex-row-reverse">
|
<HStack space={2} justifyContent="start" className="mt-2 mb-4 flex-row-reverse">
|
||||||
<Button className="focus" color={colors[variant]} onClick={handleSuccess}>
|
<Button className="focus" color={colors[variant]} onClick={handleSuccess}>
|
||||||
{confirmButtonTexts[variant]}
|
{confirmButtonTexts[variant]}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
43
src-web/hooks/useDeleteAnyGrpcRequest.tsx
Normal file
43
src-web/hooks/useDeleteAnyGrpcRequest.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { invoke } from '@tauri-apps/api';
|
||||||
|
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 { useConfirm } from './useConfirm';
|
||||||
|
import { grpcRequestsQueryKey } from './useGrpcRequests';
|
||||||
|
|
||||||
|
export function useDeleteAnyGrpcRequest() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const confirm = useConfirm();
|
||||||
|
|
||||||
|
return useMutation<GrpcRequest | null, string, string>({
|
||||||
|
mutationFn: async (id) => {
|
||||||
|
const request = await getGrpcRequest(id);
|
||||||
|
if (request == null) return null;
|
||||||
|
|
||||||
|
const confirmed = await confirm({
|
||||||
|
id: 'delete-grpc-request',
|
||||||
|
title: 'Delete Request',
|
||||||
|
variant: 'delete',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
Permanently delete <InlineCode>{fallbackRequestName(request)}</InlineCode>?
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
if (!confirmed) return null;
|
||||||
|
return invoke('cmd_delete_grpc_request', { requestId: id });
|
||||||
|
},
|
||||||
|
onSettled: () => trackEvent('GrpcRequest', 'Delete'),
|
||||||
|
onSuccess: async (request) => {
|
||||||
|
if (request === null) return;
|
||||||
|
|
||||||
|
const { workspaceId, id: requestId } = request;
|
||||||
|
queryClient.setQueryData<GrpcRequest[]>(grpcRequestsQueryKey({ workspaceId }), (requests) =>
|
||||||
|
(requests ?? []).filter((r) => r.id !== requestId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -9,13 +9,15 @@ import { useConfirm } from './useConfirm';
|
|||||||
import { httpRequestsQueryKey } from './useHttpRequests';
|
import { httpRequestsQueryKey } from './useHttpRequests';
|
||||||
import { httpResponsesQueryKey } from './useHttpResponses';
|
import { httpResponsesQueryKey } from './useHttpResponses';
|
||||||
|
|
||||||
export function useDeleteAnyRequest() {
|
export function useDeleteAnyHttpRequest() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
return useMutation<HttpRequest | null, string, string>({
|
return useMutation<HttpRequest | null, string, string>({
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
const request = await getHttpRequest(id);
|
const request = await getHttpRequest(id);
|
||||||
|
if (request == null) return null;
|
||||||
|
|
||||||
const confirmed = await confirm({
|
const confirmed = await confirm({
|
||||||
id: 'delete-request',
|
id: 'delete-request',
|
||||||
title: 'Delete Request',
|
title: 'Delete Request',
|
||||||
@@ -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 { useDeleteAnyRequest } from './useDeleteAnyRequest';
|
import { useDeleteAnyHttpRequest } from './useDeleteAnyHttpRequest';
|
||||||
|
|
||||||
export function useDeleteRequest(id: string | null) {
|
export function useDeleteRequest(id: string | null) {
|
||||||
const deleteAnyRequest = useDeleteAnyRequest();
|
const deleteAnyRequest = useDeleteAnyHttpRequest();
|
||||||
|
|
||||||
return useMutation<HttpRequest | null, string>({
|
return useMutation<HttpRequest | null, string>({
|
||||||
mutationFn: () => deleteAnyRequest.mutateAsync(id ?? 'n/a'),
|
mutationFn: () => deleteAnyRequest.mutateAsync(id ?? 'n/a'),
|
||||||
|
|||||||
Reference in New Issue
Block a user