Working sidebar actions for grpc

This commit is contained in:
Gregory Schier
2024-02-07 00:02:02 -08:00
parent d668244f9b
commit 9c35f7c85c
9 changed files with 137 additions and 50 deletions

View File

@@ -24,7 +24,6 @@ use tonic_reflection::pb::server_reflection_response::MessageResponse;
use tonic_reflection::pb::ServerReflectionRequest;
pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool, String> {
println!("FILL POOL FROM FILES");
let mut pool = DescriptorPool::new();
let random_file_name = format!("{}.desc", uuid::Uuid::new_v4());
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())?;
if !output.status.success() {
return Err(format!(
@@ -75,21 +72,7 @@ pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool,
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> {
println!("FILL POOL FROM URI");
let mut pool = DescriptorPool::new();
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)
}
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(
reflect_client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
) -> Result<Vec<String>, String> {

View File

@@ -44,16 +44,17 @@ use crate::http::send_http_request;
use crate::models::{
cancel_pending_grpc_connections, cancel_pending_responses, create_response,
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_workspace, duplicate_grpc_request, duplicate_http_request, get_cookie_jar,
get_environment, get_folder, get_grpc_request, get_http_request, get_http_response,
get_key_value_raw, get_or_create_settings, get_workspace, get_workspace_export_resources,
list_cookie_jars, list_environments, list_folders, list_grpc_connections, list_grpc_messages,
list_grpc_requests, list_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_message, upsert_grpc_request, upsert_http_request,
upsert_workspace, CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection,
GrpcMessage, GrpcRequest, HttpRequest, HttpResponse, KeyValue, Settings, Workspace,
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
get_cookie_jar, get_environment, get_folder, get_grpc_request, get_http_request,
get_http_response, get_key_value_raw, get_or_create_settings, get_workspace,
get_workspace_export_resources, list_cookie_jars, list_environments, list_folders,
list_grpc_connections, list_grpc_messages, list_grpc_requests, list_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_message,
upsert_grpc_request, upsert_http_request, upsert_workspace, CookieJar, Environment,
EnvironmentVariable, Folder, GrpcConnection, GrpcMessage, GrpcRequest, HttpRequest,
HttpResponse, KeyValue, Settings, Workspace,
};
use crate::plugin::{ImportResources, ImportResult};
use crate::updates::{update_mode_from_str, UpdateMode, YaakUpdater};
@@ -103,7 +104,6 @@ async fn cmd_grpc_reflect(
.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 {
println!("REFLECT FROM FILES");
grpc_handle
.lock()
.await
@@ -1331,8 +1331,8 @@ async fn cmd_update_http_request(
async fn cmd_delete_grpc_request(
app_handle: AppHandle,
request_id: &str,
) -> Result<HttpRequest, String> {
delete_http_request(&app_handle, request_id)
) -> Result<GrpcRequest, String> {
delete_grpc_request(&app_handle, request_id)
.await
.map_err(|e| e.to_string())
}

View File

@@ -1379,6 +1379,26 @@ pub async fn list_responses_by_workspace_id(
.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(
app_handle: &AppHandle,
id: &str,

View File

@@ -65,6 +65,7 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
<div className="overflow-y-auto h-full">
{...messages.map((m) => (
<HStack
role="button"
key={m.id}
space={2}
onClick={() => {
@@ -72,7 +73,10 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
else setActiveMessageId(m.id);
}}
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
className={
@@ -80,8 +84,22 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
}
icon={m.isInfo ? 'info' : m.isServer ? 'arrowBigDownDash' : 'arrowBigUpDash'}
/>
<div className="w-full truncate text-gray-800 text-2xs">{m.message}</div>
<div className="text-gray-600 text-2xs">{format(m.createdAt, 'HH:mm:ss')}</div>
<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>
))}
</div>

View File

@@ -11,7 +11,8 @@ import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes';
import { useCreateFolder } from '../hooks/useCreateFolder';
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 { useDeleteRequest } from '../hooks/useDeleteRequest';
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
@@ -36,6 +37,7 @@ import { fallbackRequestName } from '../lib/fallbackRequestName';
import { NAMESPACE_NO_SYNC } from '../lib/keyValueStore';
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '../lib/models';
import { isResponseLoading } from '../lib/models';
import type { DropdownItem } from './core/Dropdown';
import { ContextMenu } from './core/Dropdown';
import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode';
@@ -65,7 +67,8 @@ export function Sidebar({ className }: Props) {
const httpRequests = useHttpRequests();
const grpcRequests = useGrpcRequests();
const folders = useFolders();
const deleteAnyRequest = useDeleteAnyRequest();
const deleteAnyHttpRequest = useDeleteAnyHttpRequest();
const deleteAnyGrpcRequest = useDeleteAnyGrpcRequest();
const activeWorkspace = useActiveWorkspace();
const duplicateHttpRequest = useDuplicateHttpRequest({
id: activeRequest?.id ?? null,
@@ -223,9 +226,10 @@ export function Sidebar({ className }: Props) {
const selected = selectableRequests.find((r) => r.id === selectedId);
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);
@@ -683,15 +687,19 @@ const SidebarItem = forwardRef(function SidebarItem(
},
]
: [
{
key: 'sendRequest',
label: 'Send',
hotKeyAction: 'http_request.send',
hotKeyLabelOnly: true, // Already bound in URL bar
leftSlot: <Icon icon="sendHorizontal" />,
onSelect: () => sendRequest.mutate(),
},
{ type: 'separator' },
...((itemModel === 'http_request'
? [
{
key: 'sendRequest',
label: 'Send',
hotKeyAction: 'http_request.send',
hotKeyLabelOnly: true, // Already bound in URL bar
leftSlot: <Icon icon="sendHorizontal" />,
onSelect: () => sendRequest.mutate(),
},
{ type: 'separator' },
]
: []) as DropdownItem[]),
{
key: 'duplicateRequest',
label: 'Duplicate',

View File

@@ -30,7 +30,7 @@ export function Confirm({ onHide, onResult, variant = 'confirm' }: ConfirmProps)
};
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}>
{confirmButtonTexts[variant]}
</Button>

View 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),
);
},
});
}

View File

@@ -9,13 +9,15 @@ import { useConfirm } from './useConfirm';
import { httpRequestsQueryKey } from './useHttpRequests';
import { httpResponsesQueryKey } from './useHttpResponses';
export function useDeleteAnyRequest() {
export function useDeleteAnyHttpRequest() {
const queryClient = useQueryClient();
const confirm = useConfirm();
return useMutation<HttpRequest | null, string, string>({
mutationFn: async (id) => {
const request = await getHttpRequest(id);
if (request == null) return null;
const confirmed = await confirm({
id: 'delete-request',
title: 'Delete Request',

View File

@@ -1,9 +1,9 @@
import { useMutation } from '@tanstack/react-query';
import type { HttpRequest } from '../lib/models';
import { useDeleteAnyRequest } from './useDeleteAnyRequest';
import { useDeleteAnyHttpRequest } from './useDeleteAnyHttpRequest';
export function useDeleteRequest(id: string | null) {
const deleteAnyRequest = useDeleteAnyRequest();
const deleteAnyRequest = useDeleteAnyHttpRequest();
return useMutation<HttpRequest | null, string>({
mutationFn: () => deleteAnyRequest.mutateAsync(id ?? 'n/a'),