From f2955c26c1e4ee81302f9f260414dfce0b0824a9 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Thu, 22 Feb 2024 19:51:30 -0800 Subject: [PATCH] Everything in messages now --- ...79cdd69210f3dc2076aedcadeba8e34dcb6e.json} | 20 ++- ...e891cb8a9e1ba6e7a60fe9e24292a3f97dca3.json | 12 -- ...04c9222645976e3433e32e190f4ee4bf100d.json} | 20 ++- ...73b4c9dbd19cd764e97817c7de30209d21af9.json | 12 ++ src-tauri/migrations/20240203164833_grpc.sql | 80 +++++----- src-tauri/src/main.rs | 141 ++++++++++-------- src-tauri/src/models.rs | 40 +++-- .../components/GrpcConnectionMessagesPane.tsx | 91 +++-------- src-web/lib/formatters.ts | 10 +- src-web/lib/models.ts | 10 +- 10 files changed, 231 insertions(+), 205 deletions(-) rename src-tauri/.sqlx/{query-737045ddd5f8ba3454425e82b9d3943f93649742d8f78613e01d322745e47ebd.json => query-18ada3bb42c29f1940ab2e61961d79cdd69210f3dc2076aedcadeba8e34dcb6e.json} (67%) delete mode 100644 src-tauri/.sqlx/query-3dce053aef78e831db2369f3c49e891cb8a9e1ba6e7a60fe9e24292a3f97dca3.json rename src-tauri/.sqlx/{query-20d6b878bb8d16bde3e78e22cf801b5b191905d867091bb54a210256a0145a17.json => query-92d8f003a8f7df692345f2d2fd2504c9222645976e3433e32e190f4ee4bf100d.json} (68%) create mode 100644 src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json diff --git a/src-tauri/.sqlx/query-737045ddd5f8ba3454425e82b9d3943f93649742d8f78613e01d322745e47ebd.json b/src-tauri/.sqlx/query-18ada3bb42c29f1940ab2e61961d79cdd69210f3dc2076aedcadeba8e34dcb6e.json similarity index 67% rename from src-tauri/.sqlx/query-737045ddd5f8ba3454425e82b9d3943f93649742d8f78613e01d322745e47ebd.json rename to src-tauri/.sqlx/query-18ada3bb42c29f1940ab2e61961d79cdd69210f3dc2076aedcadeba8e34dcb6e.json index d20b2dc2..6f205863 100644 --- a/src-tauri/.sqlx/query-737045ddd5f8ba3454425e82b9d3943f93649742d8f78613e01d322745e47ebd.json +++ b/src-tauri/.sqlx/query-18ada3bb42c29f1940ab2e61961d79cdd69210f3dc2076aedcadeba8e34dcb6e.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n id, model, workspace_id, request_id, connection_id, created_at, content,\n event_type AS \"event_type!: GrpcEventType\",\n metadata AS \"metadata!: sqlx::types::Json>\"\n FROM grpc_events\n WHERE connection_id = ?\n ", + "query": "\n SELECT\n id, model, workspace_id, request_id, connection_id, created_at, content, status, error,\n event_type AS \"event_type!: GrpcEventType\",\n metadata AS \"metadata!: sqlx::types::Json>\"\n FROM grpc_events\n WHERE connection_id = ?\n ", "describe": { "columns": [ { @@ -39,13 +39,23 @@ "type_info": "Text" }, { - "name": "event_type!: GrpcEventType", + "name": "status", "ordinal": 7, + "type_info": "Int64" + }, + { + "name": "error", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "event_type!: GrpcEventType", + "ordinal": 9, "type_info": "Text" }, { "name": "metadata!: sqlx::types::Json>", - "ordinal": 8, + "ordinal": 10, "type_info": "Text" } ], @@ -60,9 +70,11 @@ false, false, false, + true, + true, false, false ] }, - "hash": "737045ddd5f8ba3454425e82b9d3943f93649742d8f78613e01d322745e47ebd" + "hash": "18ada3bb42c29f1940ab2e61961d79cdd69210f3dc2076aedcadeba8e34dcb6e" } diff --git a/src-tauri/.sqlx/query-3dce053aef78e831db2369f3c49e891cb8a9e1ba6e7a60fe9e24292a3f97dca3.json b/src-tauri/.sqlx/query-3dce053aef78e831db2369f3c49e891cb8a9e1ba6e7a60fe9e24292a3f97dca3.json deleted file mode 100644 index 009959d0..00000000 --- a/src-tauri/.sqlx/query-3dce053aef78e831db2369f3c49e891cb8a9e1ba6e7a60fe9e24292a3f97dca3.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO grpc_events (\n id, workspace_id, request_id, connection_id, content, event_type, metadata\n )\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n content = excluded.content,\n event_type = excluded.event_type,\n metadata = excluded.metadata\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 7 - }, - "nullable": [] - }, - "hash": "3dce053aef78e831db2369f3c49e891cb8a9e1ba6e7a60fe9e24292a3f97dca3" -} diff --git a/src-tauri/.sqlx/query-20d6b878bb8d16bde3e78e22cf801b5b191905d867091bb54a210256a0145a17.json b/src-tauri/.sqlx/query-92d8f003a8f7df692345f2d2fd2504c9222645976e3433e32e190f4ee4bf100d.json similarity index 68% rename from src-tauri/.sqlx/query-20d6b878bb8d16bde3e78e22cf801b5b191905d867091bb54a210256a0145a17.json rename to src-tauri/.sqlx/query-92d8f003a8f7df692345f2d2fd2504c9222645976e3433e32e190f4ee4bf100d.json index e6aaae04..f6ed8350 100644 --- a/src-tauri/.sqlx/query-20d6b878bb8d16bde3e78e22cf801b5b191905d867091bb54a210256a0145a17.json +++ b/src-tauri/.sqlx/query-92d8f003a8f7df692345f2d2fd2504c9222645976e3433e32e190f4ee4bf100d.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT\n id, model, workspace_id, request_id, connection_id, created_at, content,\n event_type AS \"event_type!: GrpcEventType\",\n metadata AS \"metadata!: sqlx::types::Json>\"\n FROM grpc_events\n WHERE id = ?\n ", + "query": "\n SELECT\n id, model, workspace_id, request_id, connection_id, created_at, content, status, error,\n event_type AS \"event_type!: GrpcEventType\",\n metadata AS \"metadata!: sqlx::types::Json>\"\n FROM grpc_events\n WHERE id = ?\n ", "describe": { "columns": [ { @@ -39,13 +39,23 @@ "type_info": "Text" }, { - "name": "event_type!: GrpcEventType", + "name": "status", "ordinal": 7, + "type_info": "Int64" + }, + { + "name": "error", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "event_type!: GrpcEventType", + "ordinal": 9, "type_info": "Text" }, { "name": "metadata!: sqlx::types::Json>", - "ordinal": 8, + "ordinal": 10, "type_info": "Text" } ], @@ -60,9 +70,11 @@ false, false, false, + true, + true, false, false ] }, - "hash": "20d6b878bb8d16bde3e78e22cf801b5b191905d867091bb54a210256a0145a17" + "hash": "92d8f003a8f7df692345f2d2fd2504c9222645976e3433e32e190f4ee4bf100d" } diff --git a/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json b/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json new file mode 100644 index 00000000..58dd7b11 --- /dev/null +++ b/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO grpc_events (\n id, workspace_id, request_id, connection_id, content, event_type, metadata, \n status, error\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n content = excluded.content,\n event_type = excluded.event_type,\n metadata = excluded.metadata,\n status = excluded.status,\n error = excluded.error\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 9 + }, + "nullable": [] + }, + "hash": "df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9" +} diff --git a/src-tauri/migrations/20240203164833_grpc.sql b/src-tauri/migrations/20240203164833_grpc.sql index ce0fae90..aa1494c0 100644 --- a/src-tauri/migrations/20240203164833_grpc.sql +++ b/src-tauri/migrations/20240203164833_grpc.sql @@ -1,67 +1,69 @@ CREATE TABLE grpc_requests ( - id TEXT NOT NULL + id TEXT NOT NULL PRIMARY KEY, - model TEXT DEFAULT 'grpc_request' NOT NULL, - workspace_id TEXT NOT NULL + model TEXT DEFAULT 'grpc_request' NOT NULL, + workspace_id TEXT NOT NULL REFERENCES workspaces ON DELETE CASCADE, - folder_id TEXT NULL + folder_id TEXT NULL REFERENCES folders ON DELETE CASCADE, - created_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - updated_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - name TEXT NOT NULL, - sort_priority REAL NOT NULL, - url TEXT NOT NULL, - service TEXT NULL, - method TEXT NULL, - message TEXT NOT NULL, - proto_files TEXT DEFAULT '[]' NOT NULL, - authentication TEXT DEFAULT '{}' NOT NULL, - authentication_type TEXT NULL, - metadata TEXT DEFAULT '[]' NOT NULL + created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + name TEXT NOT NULL, + sort_priority REAL NOT NULL, + url TEXT NOT NULL, + service TEXT NULL, + method TEXT NULL, + message TEXT NOT NULL, + proto_files TEXT DEFAULT '[]' NOT NULL, + authentication TEXT DEFAULT '{}' NOT NULL, + authentication_type TEXT NULL, + metadata TEXT DEFAULT '[]' NOT NULL ); CREATE TABLE grpc_connections ( - id TEXT NOT NULL + id TEXT NOT NULL PRIMARY KEY, - model TEXT DEFAULT 'grpc_connection' NOT NULL, - workspace_id TEXT NOT NULL + model TEXT DEFAULT 'grpc_connection' NOT NULL, + workspace_id TEXT NOT NULL REFERENCES workspaces ON DELETE CASCADE, - request_id TEXT NOT NULL + request_id TEXT NOT NULL REFERENCES grpc_requests ON DELETE CASCADE, - created_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - updated_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - url TEXT NOT NULL, - service TEXT NOT NULL, - method TEXT NOT NULL, - status INTEGER DEFAULT -1 NOT NULL, - error TEXT NULL, - elapsed INTEGER DEFAULT 0 NOT NULL, - trailers TEXT DEFAULT '{}' NOT NULL + created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + url TEXT NOT NULL, + service TEXT NOT NULL, + method TEXT NOT NULL, + status INTEGER DEFAULT -1 NOT NULL, + error TEXT NULL, + elapsed INTEGER DEFAULT 0 NOT NULL, + trailers TEXT DEFAULT '{}' NOT NULL ); CREATE TABLE grpc_events ( - id TEXT NOT NULL + id TEXT NOT NULL PRIMARY KEY, - model TEXT DEFAULT 'grpc_event' NOT NULL, - workspace_id TEXT NOT NULL + model TEXT DEFAULT 'grpc_event' NOT NULL, + workspace_id TEXT NOT NULL REFERENCES workspaces ON DELETE CASCADE, - request_id TEXT NOT NULL + request_id TEXT NOT NULL REFERENCES grpc_requests ON DELETE CASCADE, - connection_id TEXT NOT NULL + connection_id TEXT NOT NULL REFERENCES grpc_connections ON DELETE CASCADE, - created_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - updated_at DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, - metadata TEXT DEFAULT '{}' NOT NULL, - event_type TEXT NOT NULL, - content TEXT NOT NULL + created_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + updated_at DATETIME DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) NOT NULL, + metadata TEXT DEFAULT '{}' NOT NULL, + event_type TEXT NOT NULL, + status INTEGER NULL, + error TEXT NULL, + content TEXT NOT NULL ); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 50c13869..892875ca 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -340,7 +340,7 @@ async fn cmd_grpc_go( let grpc_listen = { let w = w.clone(); - let base_msg = base_msg.clone(); + let base_event = base_msg.clone(); let req = req.clone(); let workspace = workspace.clone(); let environment = environment.clone(); @@ -350,15 +350,14 @@ async fn cmd_grpc_go( req.message }; let msg = render::render(&raw_msg, &workspace, environment.as_ref()); - let conn_id = conn_id.clone(); upsert_grpc_event( &w, &GrpcEvent { content: format!("Connecting to {}", req.url), - event_type: GrpcEventType::Info, + event_type: GrpcEventType::ConnectionStart, metadata: Json(metadata.clone()), - ..base_msg.clone() + ..base_event.clone() }, ) .await @@ -405,7 +404,7 @@ async fn cmd_grpc_go( &GrpcEvent { event_type: GrpcEventType::ClientMessage, content: msg, - ..base_msg.clone() + ..base_event.clone() }, ) .await @@ -419,13 +418,13 @@ async fn cmd_grpc_go( &GrpcEvent { metadata: Json(metadata_to_map(msg.metadata().clone())), content: if msg.metadata().len() == 0 { - "Connection established" + "Received response" } else { - "Received metadata" + "Received response with metadata" } .to_string(), event_type: GrpcEventType::Info, - ..base_msg.clone() + ..base_event.clone() }, ) .await @@ -435,30 +434,32 @@ async fn cmd_grpc_go( &GrpcEvent { content: serialize_message(&msg.into_inner()).unwrap(), event_type: GrpcEventType::ServerMessage, - ..base_msg.clone() + ..base_event.clone() }, ) .await .unwrap(); - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { - elapsed: start.elapsed().as_millis() as i64, - status: Code::Ok as i64, - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + &GrpcEvent { + content: "Connection complete".to_string(), + event_type: GrpcEventType::ConnectionEnd, + status: Some(Code::Ok as i64), + ..base_event.clone() }, ) .await .unwrap(); } Some(Err(e)) => { - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { + &GrpcEvent { + content: "Failed to connect".to_string(), + event_type: GrpcEventType::ConnectionEnd, error: Some(e.to_string()), - elapsed: start.elapsed().as_millis() as i64, - status: Code::Unknown as i64, - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + status: Some(Code::Unknown as i64), + ..base_event.clone() }, ) .await @@ -470,33 +471,34 @@ async fn cmd_grpc_go( } let mut stream = match maybe_stream { - Some(Ok(Ok(s))) => { + Some(Ok(Ok(stream))) => { upsert_grpc_event( &w, &GrpcEvent { - metadata: Json(metadata_to_map(s.metadata().clone())), - content: if s.metadata().len() == 0 { - "Connection established" + metadata: Json(metadata_to_map(stream.metadata().clone())), + content: if stream.metadata().len() == 0 { + "Received response" } else { - "Received metadata" + "Received response with metadata" } - .to_string(), + .to_string(), event_type: GrpcEventType::Info, - ..base_msg.clone() + ..base_event.clone() }, ) - .await - .unwrap(); - s.into_inner() + .await + .unwrap(); + stream.into_inner() } Some(Ok(Err(e))) => { - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { + &GrpcEvent { error: Some(e.message().to_string()), - status: e.code() as i64, - elapsed: start.elapsed().as_millis() as i64, - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + status: Some(e.code() as i64), + content: e.code().description().to_string(), + event_type: GrpcEventType::ConnectionEnd, + ..base_event.clone() }, ) .await @@ -504,13 +506,14 @@ async fn cmd_grpc_go( return; } Some(Err(e)) => { - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { + &GrpcEvent { error: Some(e), - status: Code::Unknown as i64, - elapsed: start.elapsed().as_millis() as i64, - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + status: Some(Code::Unknown as i64), + content: "Unknown error".to_string(), + event_type: GrpcEventType::ConnectionEnd, + ..base_event.clone() }, ) .await @@ -529,7 +532,7 @@ async fn cmd_grpc_go( &GrpcEvent { content: message, event_type: GrpcEventType::ServerMessage, - ..base_msg.clone() + ..base_event.clone() }, ) .await @@ -541,13 +544,14 @@ async fn cmd_grpc_go( .await .unwrap_or_default() .unwrap_or_default(); - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { - elapsed: start.elapsed().as_millis() as i64, - status: Code::Unavailable as i64, - trailers: Json(metadata_to_map(trailers)), - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + &GrpcEvent { + content: "Connection complete".to_string(), + status: Some(Code::Unavailable as i64), + metadata: Json(metadata_to_map(trailers)), + event_type: GrpcEventType::ConnectionEnd, + ..base_event.clone() }, ) .await @@ -555,13 +559,14 @@ async fn cmd_grpc_go( break; } Err(status) => { - upsert_grpc_connection( + upsert_grpc_event( &w, - &GrpcConnection { - elapsed: start.elapsed().as_millis() as i64, - status: Code::Unavailable as i64, - trailers: Json(metadata_to_map(status.metadata().clone())), - ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + &GrpcEvent { + content: status.to_string(), + status: Some(status.code() as i64), + metadata: Json(metadata_to_map(status.metadata().clone())), + event_type: GrpcEventType::ConnectionEnd, + ..base_event.clone() }, ) .await @@ -578,16 +583,32 @@ async fn cmd_grpc_go( let w = w.clone(); tokio::select! { _ = grpc_listen => { - // upsert_grpc_connection( - // &w, - // &GrpcConnection{ - // elapsed: start.elapsed().as_millis() as i64, - // status: Code::Ok as i64, - // ..conn - // }, - // ).await.unwrap(); + let events = list_grpc_events(&w, &conn_id) + .await + .unwrap(); + let closed_event = events + .iter() + .find(|e| GrpcEventType::ConnectionEnd == e.event_type); + let closed_status = closed_event.and_then(|e| e.status).unwrap_or(Code::Unavailable as i64); + upsert_grpc_connection( + &w, + &GrpcConnection{ + elapsed: start.elapsed().as_millis() as i64, + status: closed_status, + ..get_grpc_connection(&w, &conn_id).await.unwrap().clone() + }, + ).await.unwrap(); }, _ = cancelled_rx.changed() => { + upsert_grpc_event( + &w, + &GrpcEvent { + content: "Cancelled".to_string(), + event_type: GrpcEventType::ConnectionEnd, + status: Some(Code::Cancelled as i64), + ..base_msg.clone() + }, + ).await.unwrap(); upsert_grpc_connection( &w, &GrpcConnection { diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index e6ac0a35..c802e4ef 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -237,7 +237,7 @@ pub struct GrpcConnection { pub trailers: Json>, } -#[derive(sqlx::Type, Debug, Clone, Serialize, Deserialize)] +#[derive(sqlx::Type, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] #[serde(rename_all = "snake_case")] #[sqlx(rename_all = "snake_case")] pub enum GrpcEventType { @@ -245,7 +245,8 @@ pub enum GrpcEventType { Error, ClientMessage, ServerMessage, - ConnectionResponse, + ConnectionStart, + ConnectionEnd, } impl Default for GrpcEventType { @@ -266,6 +267,8 @@ pub struct GrpcEvent { pub content: String, pub event_type: GrpcEventType, pub metadata: Json>, + pub status: Option, + pub error: Option, } #[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)] @@ -699,32 +702,37 @@ pub async fn list_grpc_connections( pub async fn upsert_grpc_event( mgr: &impl Manager, - message: &GrpcEvent, + event: &GrpcEvent, ) -> Result { let db = get_db(mgr).await; - let id = match message.id.as_str() { + let id = match event.id.as_str() { "" => generate_id(Some("ge")), - _ => message.id.to_string(), + _ => event.id.to_string(), }; sqlx::query!( r#" INSERT INTO grpc_events ( - id, workspace_id, request_id, connection_id, content, event_type, metadata + id, workspace_id, request_id, connection_id, content, event_type, metadata, + status, error ) - VALUES (?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET updated_at = CURRENT_TIMESTAMP, content = excluded.content, event_type = excluded.event_type, - metadata = excluded.metadata + metadata = excluded.metadata, + status = excluded.status, + error = excluded.error "#, id, - message.workspace_id, - message.request_id, - message.connection_id, - message.content, - message.event_type, - message.metadata, + event.workspace_id, + event.request_id, + event.connection_id, + event.content, + event.event_type, + event.metadata, + event.status, + event.error, ) .execute(&db) .await?; @@ -744,7 +752,7 @@ pub async fn get_grpc_event( GrpcEvent, r#" SELECT - id, model, workspace_id, request_id, connection_id, created_at, content, + id, model, workspace_id, request_id, connection_id, created_at, content, status, error, event_type AS "event_type!: GrpcEventType", metadata AS "metadata!: sqlx::types::Json>" FROM grpc_events @@ -765,7 +773,7 @@ pub async fn list_grpc_events( GrpcEvent, r#" SELECT - id, model, workspace_id, request_id, connection_id, created_at, content, + id, model, workspace_id, request_id, connection_id, created_at, content, status, error, event_type AS "event_type!: GrpcEventType", metadata AS "metadata!: sqlx::types::Json>" FROM grpc_events diff --git a/src-web/components/GrpcConnectionMessagesPane.tsx b/src-web/components/GrpcConnectionMessagesPane.tsx index 141273d2..ef4f554e 100644 --- a/src-web/components/GrpcConnectionMessagesPane.tsx +++ b/src-web/components/GrpcConnectionMessagesPane.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { format, addMilliseconds } from 'date-fns'; +import { format } from 'date-fns'; import type { CSSProperties, ReactNode } from 'react'; import React, { useEffect, useMemo, useState } from 'react'; import { useGrpcConnections } from '../hooks/useGrpcConnections'; @@ -27,48 +27,11 @@ interface Props { | 'no-method'; } -const CONNECTION_RESPONSE_EVENT_ID = 'connection_response'; - export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }: Props) { const [activeEventId, setActiveEventId] = useState(null); const connections = useGrpcConnections(activeRequest.id ?? null); const activeConnection = connections[0] ?? null; - const ogEvents = useGrpcEvents(activeConnection?.id ?? null); - - const events = useMemo(() => { - const createdAt = - activeConnection != null && - addMilliseconds(activeConnection.createdAt, activeConnection.elapsed) - .toISOString() - .replace('Z', ''); - if (activeConnection == null || activeConnection.elapsed === 0) { - return ogEvents; - } else if (activeConnection.error != null) { - return [ - ...ogEvents, - { - id: CONNECTION_RESPONSE_EVENT_ID, - eventType: 'error', - content: activeConnection.error, - metadata: activeConnection.trailers, - createdAt, - updatedAt: createdAt, - } as GrpcEvent, - ]; - } else { - return [ - ...ogEvents, - { - id: CONNECTION_RESPONSE_EVENT_ID, - eventType: activeConnection.status === 0 ? 'connection_response' : 'error', - content: `Connection ${GRPC_CODES[activeConnection.status] ?? 'closed'}`, - metadata: activeConnection.trailers, - createdAt, - updatedAt: createdAt, - } as GrpcEvent, - ]; - } - }, [activeConnection, ogEvents]); + const events = useGrpcEvents(activeConnection?.id ?? null); const activeEvent = useMemo( () => events.find((m) => m.id === activeEventId) ?? null, @@ -110,19 +73,16 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }: />
- {...events.map((m) => ( - ( + { - if (m.id === activeEventId) setActiveEventId(null); - else setActiveEventId(m.id); + if (e.id === activeEventId) setActiveEventId(null); + else setActiveEventId(e.id); }} - > - {m.content} - + /> ))}
@@ -147,11 +107,11 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }: ) : (
- {activeEvent.content} + {activeEvent.error ?? activeEvent.content}
{Object.keys(activeEvent.metadata).length === 0 ? ( - No {activeEvent.eventType === 'connection_response' ? 'trailers' : 'metadata'} + No {activeEvent.eventType === 'connection_end' ? 'trailers' : 'metadata'} ) : ( @@ -170,19 +130,16 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }: ); } -function MessageRow({ +function EventRow({ onClick, isActive, - eventType, - children, - timestamp, + event, }: { onClick?: () => void; isActive?: boolean; - eventType: GrpcEvent['eventType']; - children: ReactNode; - timestamp: string; + event: GrpcEvent; }) { + const { eventType, status, createdAt, content, error } = event; return ( ); diff --git a/src-web/lib/formatters.ts b/src-web/lib/formatters.ts index b967e458..245e89d3 100644 --- a/src-web/lib/formatters.ts +++ b/src-web/lib/formatters.ts @@ -1,8 +1,12 @@ import xmlFormat from 'xml-formatter'; +const INDENT = ' '; + export function tryFormatJson(text: string, pretty = true): string { + if (text === '') return text; + try { - if (pretty) return JSON.stringify(JSON.parse(text), null, 2); + if (pretty) return JSON.stringify(JSON.parse(text), null, INDENT); else return JSON.stringify(JSON.parse(text)); } catch (_) { return text; @@ -10,8 +14,10 @@ export function tryFormatJson(text: string, pretty = true): string { } export function tryFormatXml(text: string): string { + if (text === '') return text; + try { - return xmlFormat(text, { throwOnFailure: true, strictMode: false }); + return xmlFormat(text, { throwOnFailure: true, strictMode: false, indentation: INDENT }); } catch (_) { return text; } diff --git a/src-web/lib/models.ts b/src-web/lib/models.ts index ff4251e9..c0d97d27 100644 --- a/src-web/lib/models.ts +++ b/src-web/lib/models.ts @@ -133,7 +133,15 @@ export interface GrpcEvent extends BaseModel { readonly connectionId: string; readonly model: 'grpc_event'; content: string; - eventType: 'info' | 'error' | 'client_message' | 'server_message' | 'connection_response'; + status: number | null; + error: string | null; + eventType: + | 'info' + | 'error' + | 'client_message' + | 'server_message' + | 'connection_start' + | 'connection_end'; metadata: Record; }