mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 17:18:32 +02:00
More response info
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body_path, elapsed, error,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE id = ?\n ",
|
"query": "\n SELECT\n id, model, workspace_id, request_id, updated_at, created_at, url, status,\n status_reason, content_length, body_path, elapsed, elapsed_headers, error,\n version, remote_addr,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE id = ?\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -64,13 +64,28 @@
|
|||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "error",
|
"name": "elapsed_headers",
|
||||||
"ordinal": 12,
|
"ordinal": 12,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "error",
|
||||||
|
"ordinal": 13,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"ordinal": 14,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "remote_addr",
|
||||||
|
"ordinal": 15,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
||||||
"ordinal": 13,
|
"ordinal": 16,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -90,9 +105,12 @@
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "679a519475adeb50abf046114d3c0d1e48e103f2bb11ef47637d7f0b00ed241f"
|
"hash": "0fa6b56f8c996d14908a56928674b4b35af5fa36f63dc48b9b66ee6dfde78976"
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "\n INSERT INTO http_responses (\n id,\n request_id,\n workspace_id,\n elapsed,\n url,\n status,\n status_reason,\n content_length,\n body_path,\n headers\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 10
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "198bd086ccc87d2e6c24cb1c717f486d3ab58c0c958ede850c018fc266eade87"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "\n UPDATE http_responses SET (\n elapsed,\n url,\n status,\n status_reason,\n content_length,\n body_path,\n error,\n headers,\n updated_at\n ) = (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 9
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "294cbe19f9ddd9519ace3558df4308948082ec0ce7096855aa7d8fba519b8b4f"
|
|
||||||
}
|
|
||||||
12
src-tauri/.sqlx/query-587aedf827b00bb706c35457a75b811317e66fc84ac0906bf5513d938121a078.json
generated
Normal file
12
src-tauri/.sqlx/query-587aedf827b00bb706c35457a75b811317e66fc84ac0906bf5513d938121a078.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n UPDATE http_responses SET (\n elapsed,\n elapsed_headers,\n url,\n status,\n status_reason,\n content_length,\n body_path,\n error,\n headers,\n version,\n remote_addr,\n updated_at\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 12
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "587aedf827b00bb706c35457a75b811317e66fc84ac0906bf5513d938121a078"
|
||||||
|
}
|
||||||
12
src-tauri/.sqlx/query-a1c9a862ca6a07476cb8e7d16d73bd109c070603396a890dc717e50020d006f5.json
generated
Normal file
12
src-tauri/.sqlx/query-a1c9a862ca6a07476cb8e7d16d73bd109c070603396a890dc717e50020d006f5.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO http_responses (\n id,\n request_id,\n workspace_id,\n elapsed,\n elapsed_headers,\n url,\n status,\n status_reason,\n content_length,\n body_path,\n headers,\n version,\n remote_addr\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 13
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "a1c9a862ca6a07476cb8e7d16d73bd109c070603396a890dc717e50020d006f5"
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body_path, elapsed, error,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE request_id = ?\n ORDER BY created_at DESC\n LIMIT ?\n ",
|
"query": "\n SELECT\n id, model, workspace_id, request_id, updated_at, created_at, url, status,\n status_reason, content_length, body_path, elapsed, elapsed_headers, error,\n version, remote_addr,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE request_id = ?\n ORDER BY created_at DESC\n LIMIT ?\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -64,13 +64,28 @@
|
|||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "error",
|
"name": "elapsed_headers",
|
||||||
"ordinal": 12,
|
"ordinal": 12,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "error",
|
||||||
|
"ordinal": 13,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"ordinal": 14,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "remote_addr",
|
||||||
|
"ordinal": 15,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
||||||
"ordinal": 13,
|
"ordinal": 16,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -90,9 +105,12 @@
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "07b0c398efd1d5f8f479652de658716a9e7faef6aba6583dd209a4f290c5edd1"
|
"hash": "ac38621cd947c3be9ca0d8ea73325fe35c3866d16f6482fc32c23762f112dc83"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body_path, elapsed, error,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE workspace_id = ?\n ORDER BY created_at DESC\n ",
|
"query": "\n SELECT\n id, model, workspace_id, request_id, updated_at, created_at, url, status,\n status_reason, content_length, body_path, elapsed, elapsed_headers, error,\n version, remote_addr,\n headers AS \"headers!: sqlx::types::Json<Vec<HttpResponseHeader>>\"\n FROM http_responses\n WHERE workspace_id = ?\n ORDER BY created_at DESC\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -64,13 +64,28 @@
|
|||||||
"type_info": "Int64"
|
"type_info": "Int64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "error",
|
"name": "elapsed_headers",
|
||||||
"ordinal": 12,
|
"ordinal": 12,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "error",
|
||||||
|
"ordinal": 13,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"ordinal": 14,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "remote_addr",
|
||||||
|
"ordinal": 15,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
||||||
"ordinal": 13,
|
"ordinal": 16,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -90,9 +105,12 @@
|
|||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "3d199d371be948211f4a50c869b307f5df60784293c52397d77a187633a406dd"
|
"hash": "d5e087caa163a0c7bfbbadf07eccb80105501cf5baab706aa6792dfe90af8fc9"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE http_responses ADD COLUMN elapsed_headers INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE http_responses ADD COLUMN remote_addr TEXT;
|
||||||
|
ALTER TABLE http_responses ADD COLUMN version TEXT;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::fs;
|
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{create_dir_all, File};
|
||||||
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@@ -7,13 +7,13 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use http::header::{ACCEPT, USER_AGENT};
|
|
||||||
use http::{HeaderMap, HeaderName, HeaderValue, Method};
|
use http::{HeaderMap, HeaderName, HeaderValue, Method};
|
||||||
|
use http::header::{ACCEPT, USER_AGENT};
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use reqwest::redirect::Policy;
|
|
||||||
use reqwest::{multipart, Url};
|
use reqwest::{multipart, Url};
|
||||||
use sqlx::types::{Json, JsonValue};
|
use reqwest::redirect::Policy;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
|
use sqlx::types::{Json, JsonValue};
|
||||||
use tauri::{AppHandle, Wry};
|
use tauri::{AppHandle, Wry};
|
||||||
|
|
||||||
use crate::{emit_side_effect, models, render, response_err};
|
use crate::{emit_side_effect, models, render, response_err};
|
||||||
@@ -27,7 +27,6 @@ pub async fn send_http_request(
|
|||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
download_path: Option<PathBuf>,
|
download_path: Option<PathBuf>,
|
||||||
) -> Result<models::HttpResponse, String> {
|
) -> Result<models::HttpResponse, String> {
|
||||||
let start = std::time::Instant::now();
|
|
||||||
let environment_ref = environment.as_ref();
|
let environment_ref = environment.as_ref();
|
||||||
let workspace = models::get_workspace(&request.workspace_id, pool)
|
let workspace = models::get_workspace(&request.workspace_id, pool)
|
||||||
.await
|
.await
|
||||||
@@ -298,11 +297,13 @@ pub async fn send_http_request(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
let raw_response = client.execute(sendable_req).await;
|
let raw_response = client.execute(sendable_req).await;
|
||||||
|
|
||||||
match raw_response {
|
match raw_response {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
let mut response = response.clone();
|
let mut response = response.clone();
|
||||||
|
response.elapsed_headers = start.elapsed().as_millis() as i64;
|
||||||
let response_headers = v.headers().clone();
|
let response_headers = v.headers().clone();
|
||||||
response.status = v.status().as_u16() as i64;
|
response.status = v.status().as_u16() as i64;
|
||||||
response.status_reason = v.status().canonical_reason().map(|s| s.to_string());
|
response.status_reason = v.status().canonical_reason().map(|s| s.to_string());
|
||||||
@@ -316,8 +317,25 @@ pub async fn send_http_request(
|
|||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
response.url = v.url().to_string();
|
response.url = v.url().to_string();
|
||||||
|
response.remote_addr = v.remote_addr().map(|a| a.to_string());
|
||||||
|
response.version = match v.version() {
|
||||||
|
http::Version::HTTP_09 => Some("HTTP/0.9".to_string()),
|
||||||
|
http::Version::HTTP_10 => Some("HTTP/1.0".to_string()),
|
||||||
|
http::Version::HTTP_11 => Some("HTTP/1.1".to_string()),
|
||||||
|
http::Version::HTTP_2 => Some("HTTP/2".to_string()),
|
||||||
|
http::Version::HTTP_3 => Some("HTTP/3".to_string()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let content_length = v.content_length();
|
||||||
let body_bytes = v.bytes().await.expect("Failed to get body").to_vec();
|
let body_bytes = v.bytes().await.expect("Failed to get body").to_vec();
|
||||||
response.content_length = Some(body_bytes.len() as i64);
|
response.elapsed = start.elapsed().as_millis() as i64;
|
||||||
|
|
||||||
|
// Use content length if available, otherwise use body length
|
||||||
|
response.content_length = match content_length {
|
||||||
|
Some(l) => Some(l as i64),
|
||||||
|
None => Some(body_bytes.len() as i64),
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
// Write body to FS
|
// Write body to FS
|
||||||
@@ -344,7 +362,6 @@ pub async fn send_http_request(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.elapsed = start.elapsed().as_millis() as i64;
|
|
||||||
response = models::update_response_if_id(&response, pool)
|
response = models::update_response_if_id(&response, pool)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to update response");
|
.expect("Failed to update response");
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ extern crate objc;
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
use std::fs::{create_dir_all, File, read_to_string};
|
use std::fs::{create_dir_all, read_to_string, File};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
use fern::colors::ColoredLevelConfig;
|
use fern::colors::ColoredLevelConfig;
|
||||||
@@ -18,13 +18,13 @@ use log::{debug, error, info, warn};
|
|||||||
use rand::random;
|
use rand::random;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use sqlx::{Pool, Sqlite, SqlitePool};
|
|
||||||
use sqlx::migrate::Migrator;
|
use sqlx::migrate::Migrator;
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
use tauri::{AppHandle, RunEvent, State, Window, WindowUrl, Wry};
|
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||||
use tauri::{Manager, WindowEvent};
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use tauri::TitleBarStyle;
|
use tauri::TitleBarStyle;
|
||||||
|
use tauri::{AppHandle, RunEvent, State, Window, WindowUrl, Wry};
|
||||||
|
use tauri::{Manager, WindowEvent};
|
||||||
use tauri_plugin_log::{fern, LogTarget};
|
use tauri_plugin_log::{fern, LogTarget};
|
||||||
use tauri_plugin_window_state::{StateFlags, WindowExt};
|
use tauri_plugin_window_state::{StateFlags, WindowExt};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -292,9 +292,22 @@ async fn send_request(
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = models::create_response(&request.id, 0, "", 0, None, None, None, vec![], pool)
|
let response = models::create_response(
|
||||||
.await
|
&request.id,
|
||||||
.expect("Failed to create response");
|
0,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
pool,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create response");
|
||||||
|
|
||||||
let download_path = if let Some(p) = download_dir {
|
let download_path = if let Some(p) = download_dir {
|
||||||
Some(std::path::Path::new(p).to_path_buf())
|
Some(std::path::Path::new(p).to_path_buf())
|
||||||
|
|||||||
@@ -171,7 +171,10 @@ pub struct HttpResponse {
|
|||||||
pub error: Option<String>,
|
pub error: Option<String>,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub content_length: Option<i64>,
|
pub content_length: Option<i64>,
|
||||||
|
pub version: Option<String>,
|
||||||
pub elapsed: i64,
|
pub elapsed: i64,
|
||||||
|
pub elapsed_headers: i64,
|
||||||
|
pub remote_addr: Option<String>,
|
||||||
pub status: i64,
|
pub status: i64,
|
||||||
pub status_reason: Option<String>,
|
pub status_reason: Option<String>,
|
||||||
pub body_path: Option<String>,
|
pub body_path: Option<String>,
|
||||||
@@ -851,15 +854,19 @@ pub async fn delete_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest
|
|||||||
Ok(req)
|
Ok(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn create_response(
|
pub async fn create_response(
|
||||||
request_id: &str,
|
request_id: &str,
|
||||||
elapsed: i64,
|
elapsed: i64,
|
||||||
|
elapsed_headers: i64,
|
||||||
url: &str,
|
url: &str,
|
||||||
status: i64,
|
status: i64,
|
||||||
status_reason: Option<&str>,
|
status_reason: Option<&str>,
|
||||||
content_length: Option<i64>,
|
content_length: Option<i64>,
|
||||||
body_path: Option<&str>,
|
body_path: Option<&str>,
|
||||||
headers: Vec<HttpResponseHeader>,
|
headers: Vec<HttpResponseHeader>,
|
||||||
|
version: Option<&str>,
|
||||||
|
remote_addr: Option<&str>,
|
||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<HttpResponse, sqlx::Error> {
|
) -> Result<HttpResponse, sqlx::Error> {
|
||||||
let req = get_request(request_id, pool).await?;
|
let req = get_request(request_id, pool).await?;
|
||||||
@@ -872,25 +879,31 @@ pub async fn create_response(
|
|||||||
request_id,
|
request_id,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
elapsed,
|
elapsed,
|
||||||
|
elapsed_headers,
|
||||||
url,
|
url,
|
||||||
status,
|
status,
|
||||||
status_reason,
|
status_reason,
|
||||||
content_length,
|
content_length,
|
||||||
body_path,
|
body_path,
|
||||||
headers
|
headers,
|
||||||
|
version,
|
||||||
|
remote_addr
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
"#,
|
"#,
|
||||||
id,
|
id,
|
||||||
request_id,
|
request_id,
|
||||||
req.workspace_id,
|
req.workspace_id,
|
||||||
elapsed,
|
elapsed,
|
||||||
|
elapsed_headers,
|
||||||
url,
|
url,
|
||||||
status,
|
status,
|
||||||
status_reason,
|
status_reason,
|
||||||
content_length,
|
content_length,
|
||||||
body_path,
|
body_path,
|
||||||
headers_json,
|
headers_json,
|
||||||
|
version,
|
||||||
|
remote_addr,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -975,6 +988,7 @@ pub async fn update_response(
|
|||||||
r#"
|
r#"
|
||||||
UPDATE http_responses SET (
|
UPDATE http_responses SET (
|
||||||
elapsed,
|
elapsed,
|
||||||
|
elapsed_headers,
|
||||||
url,
|
url,
|
||||||
status,
|
status,
|
||||||
status_reason,
|
status_reason,
|
||||||
@@ -982,10 +996,13 @@ pub async fn update_response(
|
|||||||
body_path,
|
body_path,
|
||||||
error,
|
error,
|
||||||
headers,
|
headers,
|
||||||
|
version,
|
||||||
|
remote_addr,
|
||||||
updated_at
|
updated_at
|
||||||
) = (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;
|
) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) WHERE id = ?;
|
||||||
"#,
|
"#,
|
||||||
response.elapsed,
|
response.elapsed,
|
||||||
|
response.elapsed_headers,
|
||||||
response.url,
|
response.url,
|
||||||
response.status,
|
response.status,
|
||||||
response.status_reason,
|
response.status_reason,
|
||||||
@@ -993,6 +1010,8 @@ pub async fn update_response(
|
|||||||
response.body_path,
|
response.body_path,
|
||||||
response.error,
|
response.error,
|
||||||
headers_json,
|
headers_json,
|
||||||
|
response.version,
|
||||||
|
response.remote_addr,
|
||||||
response.id,
|
response.id,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
@@ -1004,8 +1023,10 @@ pub async fn get_response(id: &str, pool: &Pool<Sqlite>) -> Result<HttpResponse,
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
HttpResponse,
|
HttpResponse,
|
||||||
r#"
|
r#"
|
||||||
SELECT id, model, workspace_id, request_id, updated_at, created_at, url,
|
SELECT
|
||||||
status, status_reason, content_length, body_path, elapsed, error,
|
id, model, workspace_id, request_id, updated_at, created_at, url, status,
|
||||||
|
status_reason, content_length, body_path, elapsed, elapsed_headers, error,
|
||||||
|
version, remote_addr,
|
||||||
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
||||||
FROM http_responses
|
FROM http_responses
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
@@ -1021,15 +1042,14 @@ pub async fn find_responses(
|
|||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<Vec<HttpResponse>, sqlx::Error> {
|
) -> Result<Vec<HttpResponse>, sqlx::Error> {
|
||||||
let limit_unwrapped = match limit {
|
let limit_unwrapped = limit.unwrap_or_else(|| i64::MAX);
|
||||||
Some(l) => l,
|
|
||||||
None => i64::MAX,
|
|
||||||
};
|
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
HttpResponse,
|
HttpResponse,
|
||||||
r#"
|
r#"
|
||||||
SELECT id, model, workspace_id, request_id, updated_at, created_at, url,
|
SELECT
|
||||||
status, status_reason, content_length, body_path, elapsed, error,
|
id, model, workspace_id, request_id, updated_at, created_at, url, status,
|
||||||
|
status_reason, content_length, body_path, elapsed, elapsed_headers, error,
|
||||||
|
version, remote_addr,
|
||||||
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
||||||
FROM http_responses
|
FROM http_responses
|
||||||
WHERE request_id = ?
|
WHERE request_id = ?
|
||||||
@@ -1050,8 +1070,10 @@ pub async fn find_responses_by_workspace_id(
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
HttpResponse,
|
HttpResponse,
|
||||||
r#"
|
r#"
|
||||||
SELECT id, model, workspace_id, request_id, updated_at, created_at, url,
|
SELECT
|
||||||
status, status_reason, content_length, body_path, elapsed, error,
|
id, model, workspace_id, request_id, updated_at, created_at, url, status,
|
||||||
|
status_reason, content_length, body_path, elapsed, elapsed_headers, error,
|
||||||
|
version, remote_addr,
|
||||||
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
||||||
FROM http_responses
|
FROM http_responses
|
||||||
WHERE workspace_id = ?
|
WHERE workspace_id = ?
|
||||||
|
|||||||
@@ -1,26 +1,47 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { HttpResponse } from '../lib/models';
|
import type { HttpResponse } from '../lib/models';
|
||||||
|
import { Separator } from './core/Separator';
|
||||||
import { HStack } from './core/Stacks';
|
import { HStack } from './core/Stacks';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
headers: HttpResponse['headers'];
|
response: HttpResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ResponseHeaders({ headers }: Props) {
|
export function ResponseHeaders({ response }: Props) {
|
||||||
return (
|
return (
|
||||||
<dl className="text-xs w-full h-full font-mono overflow-auto">
|
<div className="overflow-auto h-full pb-4">
|
||||||
{headers.map((h, i) => {
|
<dl className="text-xs w-full font-mono flex flex-col">
|
||||||
return (
|
{response.headers.map((h, i) => (
|
||||||
<HStack
|
<Row key={i} label={h.name} value={h.value} labelClassName="!text-violet-600" />
|
||||||
space={3}
|
))}
|
||||||
key={i}
|
</dl>
|
||||||
className={classNames(i > 0 ? 'border-t border-highlightSecondary py-1' : 'pb-1')}
|
<Separator className="my-4">Other Info</Separator>
|
||||||
>
|
<dl className="text-xs w-full font-mono divide-highlightSecondary">
|
||||||
<dd className="w-1/3 text-violet-600 select-text cursor-text">{h.name}</dd>
|
<Row label="Version" value={response.version} />
|
||||||
<dt className="w-2/3 select-text cursor-text break-all">{h.value}</dt>
|
<Row label="Remote Address" value={response.remoteAddr} />
|
||||||
</HStack>
|
<Row label="Status" value={response.status} />
|
||||||
);
|
<Row label="Reason" value={response.statusReason} />
|
||||||
})}
|
<Row label="URL" value={response.url} />
|
||||||
</dl>
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Row({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
labelClassName,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
value: string | number;
|
||||||
|
labelClassName?: string;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<HStack space={3} className="py-0.5">
|
||||||
|
<dd className={classNames(labelClassName, 'w-1/3 text-gray-700 select-text cursor-text')}>
|
||||||
|
{label}
|
||||||
|
</dd>
|
||||||
|
<dt className="w-2/3 select-text cursor-text break-all">{value}</dt>
|
||||||
|
</HStack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,10 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
|||||||
{activeResponse.elapsed > 0 && (
|
{activeResponse.elapsed > 0 && (
|
||||||
<>
|
<>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<DurationTag millis={activeResponse.elapsed} />
|
<DurationTag
|
||||||
|
headers={activeResponse.elapsedHeaders}
|
||||||
|
total={activeResponse.elapsed}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!!activeResponse.contentLength && (
|
{!!activeResponse.contentLength && (
|
||||||
@@ -160,7 +163,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
|||||||
tabListClassName="mt-1.5"
|
tabListClassName="mt-1.5"
|
||||||
>
|
>
|
||||||
<TabContent value="headers">
|
<TabContent value="headers">
|
||||||
<ResponseHeaders headers={activeResponse?.headers ?? []} />
|
<ResponseHeaders response={activeResponse} />
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value="body">
|
<TabContent value="body">
|
||||||
{!activeResponse.contentLength ? (
|
{!activeResponse.contentLength ? (
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
interface Props {
|
interface Props {
|
||||||
millis: number;
|
total: number;
|
||||||
|
headers: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DurationTag({ millis }: Props) {
|
export function DurationTag({ total, headers }: Props) {
|
||||||
|
return (
|
||||||
|
<span title={`HEADER: ${formatMillis(headers)}\nTOTAL: ${formatMillis(total)}`}>
|
||||||
|
{formatMillis(total)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMillis(millis: number) {
|
||||||
let num;
|
let num;
|
||||||
let unit;
|
let unit;
|
||||||
|
|
||||||
@@ -17,9 +26,5 @@ export function DurationTag({ millis }: Props) {
|
|||||||
unit = 'ms';
|
unit = 'ms';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return `${Math.round(num * 10) / 10} ${unit}`;
|
||||||
<span title={`${millis} milliseconds`}>
|
|
||||||
{Math.round(num * 10) / 10} {unit}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function Separator({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div role="separator" className={classNames(className, 'flex items-center')}>
|
<div role="separator" className={classNames(className, 'flex items-center')}>
|
||||||
{children && <div className="text-xs text-gray-500 mx-2 whitespace-nowrap">{children}</div>}
|
{children && <div className="text-xs text-gray-500 mr-2 whitespace-nowrap">{children}</div>}
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
variant === 'primary' && 'bg-highlight',
|
variant === 'primary' && 'bg-highlight',
|
||||||
|
|||||||
@@ -133,7 +133,10 @@ export interface HttpResponse extends BaseModel {
|
|||||||
readonly error: string;
|
readonly error: string;
|
||||||
readonly status: number;
|
readonly status: number;
|
||||||
readonly elapsed: number;
|
readonly elapsed: number;
|
||||||
|
readonly elapsedHeaders: number;
|
||||||
readonly statusReason: string;
|
readonly statusReason: string;
|
||||||
|
readonly version: string;
|
||||||
|
readonly remoteAddr: string;
|
||||||
readonly url: string;
|
readonly url: string;
|
||||||
readonly headers: HttpHeader[];
|
readonly headers: HttpHeader[];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user