mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-18 06:49:50 +02:00
Fix text encoding and delete responses
This commit is contained in:
@@ -58,15 +58,107 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM http_responses\n WHERE id = ?\n "
|
"query": "\n DELETE FROM http_responses\n WHERE id = ?\n "
|
||||||
},
|
},
|
||||||
"0fa36011553f7ca91113459a5cefd47f990f9b548a95e475ffd6e4b017059488": {
|
"26072725d536c3cfdffd9a681d17c0ee2f246ca98e0459630a2430236d3bbdd2": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [
|
||||||
"nullable": [],
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "model",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "workspace_id",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "request_id",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "updated_at",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Datetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "created_at",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "Datetime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "url",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "status",
|
||||||
|
"ordinal": 7,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "status_reason",
|
||||||
|
"ordinal": 8,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "content_length",
|
||||||
|
"ordinal": 9,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"ordinal": 10,
|
||||||
|
"type_info": "Blob"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body_path",
|
||||||
|
"ordinal": 11,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "elapsed",
|
||||||
|
"ordinal": 12,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "error",
|
||||||
|
"ordinal": 13,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>",
|
||||||
|
"ordinal": 14,
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Right": 1
|
"Right": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "\n DELETE FROM http_responses\n WHERE request_id = ?\n "
|
"query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body, 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 "
|
||||||
},
|
},
|
||||||
"448a1d1f1866ab42c0f81fcf8eb2930bf21dfdd43ca4831bc1a198cf45ac3732": {
|
"448a1d1f1866ab42c0f81fcf8eb2930bf21dfdd43ca4831bc1a198cf45ac3732": {
|
||||||
"describe": {
|
"describe": {
|
||||||
|
|||||||
@@ -9,6 +9,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;
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{create_dir_all, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
@@ -225,7 +226,9 @@ async fn actually_send_ephemeral_request(
|
|||||||
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.content_length = Some(body_bytes.len() as i64);
|
||||||
let dir = app_handle.path_resolver().app_data_dir().unwrap();
|
let dir = app_handle.path_resolver().app_data_dir().unwrap();
|
||||||
let body_path = dir.join(response.id.clone());
|
let base_dir = dir.join("responses");
|
||||||
|
create_dir_all(base_dir.clone()).expect("Failed to create responses dir");
|
||||||
|
let body_path = base_dir.join(response.id.clone());
|
||||||
let mut f = File::options()
|
let mut f = File::options()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
|
|||||||
@@ -154,9 +154,7 @@ pub async fn get_workspace(id: &str, pool: &Pool<Sqlite>) -> Result<Workspace, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_workspace(id: &str, pool: &Pool<Sqlite>) -> Result<Workspace, sqlx::Error> {
|
pub async fn delete_workspace(id: &str, pool: &Pool<Sqlite>) -> Result<Workspace, sqlx::Error> {
|
||||||
let workspace = get_workspace(id, pool)
|
let workspace = get_workspace(id, pool).await?;
|
||||||
.await
|
|
||||||
.expect("Failed to get request to delete");
|
|
||||||
let _ = sqlx::query!(
|
let _ = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
DELETE FROM workspaces
|
DELETE FROM workspaces
|
||||||
@@ -166,6 +164,11 @@ pub async fn delete_workspace(id: &str, pool: &Pool<Sqlite>) -> Result<Workspace
|
|||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
for r in find_responses_by_workspace_id(id, pool).await? {
|
||||||
|
delete_response(&r.id, pool).await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(workspace)
|
Ok(workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,16 +188,13 @@ pub async fn create_workspace(
|
|||||||
description,
|
description,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await?;
|
||||||
.expect("Failed to insert new workspace");
|
|
||||||
|
|
||||||
get_workspace(&id, pool).await
|
get_workspace(&id, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn duplicate_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest, sqlx::Error> {
|
pub async fn duplicate_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest, sqlx::Error> {
|
||||||
let existing = get_request(id, pool)
|
let existing = get_request(id, pool).await?;
|
||||||
.await
|
|
||||||
.expect("Failed to get request to duplicate");
|
|
||||||
|
|
||||||
// TODO: Figure out how to make this better
|
// TODO: Figure out how to make this better
|
||||||
let b2;
|
let b2;
|
||||||
@@ -289,8 +289,7 @@ pub async fn upsert_request(
|
|||||||
sort_priority,
|
sort_priority,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await?;
|
||||||
.expect("Failed to insert new request");
|
|
||||||
get_request(id, pool).await
|
get_request(id, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,9 +353,7 @@ pub async fn get_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest, sqlx::Error> {
|
pub async fn delete_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest, sqlx::Error> {
|
||||||
let req = get_request(id, pool)
|
let req = get_request(id, pool).await?;
|
||||||
.await
|
|
||||||
.expect("Failed to get request to delete");
|
|
||||||
let _ = sqlx::query!(
|
let _ = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
DELETE FROM http_requests
|
DELETE FROM http_requests
|
||||||
@@ -367,6 +364,8 @@ pub async fn delete_request(id: &str, pool: &Pool<Sqlite>) -> Result<HttpRequest
|
|||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
delete_all_responses(id, pool).await?;
|
||||||
|
|
||||||
Ok(req)
|
Ok(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,9 +381,7 @@ pub async fn create_response(
|
|||||||
headers: Vec<HttpResponseHeader>,
|
headers: Vec<HttpResponseHeader>,
|
||||||
pool: &Pool<Sqlite>,
|
pool: &Pool<Sqlite>,
|
||||||
) -> Result<HttpResponse, sqlx::Error> {
|
) -> Result<HttpResponse, sqlx::Error> {
|
||||||
let req = get_request(request_id, pool)
|
let req = get_request(request_id, pool).await?;
|
||||||
.await
|
|
||||||
.expect("Failed to get request");
|
|
||||||
let id = generate_id("rp");
|
let id = generate_id("rp");
|
||||||
let headers_json = Json(headers);
|
let headers_json = Json(headers);
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
@@ -417,8 +414,7 @@ pub async fn create_response(
|
|||||||
headers_json,
|
headers_json,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await?;
|
||||||
.expect("Failed to insert new response");
|
|
||||||
|
|
||||||
get_response(&id, pool).await
|
get_response(&id, pool).await
|
||||||
}
|
}
|
||||||
@@ -447,8 +443,8 @@ pub async fn update_workspace(
|
|||||||
workspace.id,
|
workspace.id,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await?;
|
||||||
.expect("Failed to update workspace");
|
|
||||||
get_workspace(&workspace.id, pool).await
|
get_workspace(&workspace.id, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,8 +480,7 @@ pub async fn update_response(
|
|||||||
response.id,
|
response.id,
|
||||||
)
|
)
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await
|
.await?;
|
||||||
.expect("Failed to update response");
|
|
||||||
get_response(&response.id, pool).await
|
get_response(&response.id, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,10 +520,28 @@ pub async fn find_responses(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_responses_by_workspace_id(
|
||||||
|
workspace_id: &str,
|
||||||
|
pool: &Pool<Sqlite>,
|
||||||
|
) -> Result<Vec<HttpResponse>, sqlx::Error> {
|
||||||
|
sqlx::query_as!(
|
||||||
|
HttpResponse,
|
||||||
|
r#"
|
||||||
|
SELECT id, model, workspace_id, request_id, updated_at, created_at, url,
|
||||||
|
status, status_reason, content_length, body, body_path, elapsed, error,
|
||||||
|
headers AS "headers!: sqlx::types::Json<Vec<HttpResponseHeader>>"
|
||||||
|
FROM http_responses
|
||||||
|
WHERE workspace_id = ?
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
"#,
|
||||||
|
workspace_id,
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_response(id: &str, pool: &Pool<Sqlite>) -> Result<HttpResponse, sqlx::Error> {
|
pub async fn delete_response(id: &str, pool: &Pool<Sqlite>) -> Result<HttpResponse, sqlx::Error> {
|
||||||
let resp = get_response(id, pool)
|
let resp = get_response(id, pool).await?;
|
||||||
.await
|
|
||||||
.expect("Failed to get response to delete");
|
|
||||||
|
|
||||||
// Delete the body file if it exists
|
// Delete the body file if it exists
|
||||||
if let Some(p) = resp.body_path.clone() {
|
if let Some(p) = resp.body_path.clone() {
|
||||||
|
|||||||
@@ -15,14 +15,14 @@
|
|||||||
"allowlist": {
|
"allowlist": {
|
||||||
"all": false,
|
"all": false,
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"assetScope": ["$APPDATA/*"],
|
"assetScope": ["$APPDATA/responses/*"],
|
||||||
"asset": true
|
"asset": true
|
||||||
},
|
},
|
||||||
"fs": {
|
"fs": {
|
||||||
"readFile": true,
|
"readFile": true,
|
||||||
"scope": [
|
"scope": [
|
||||||
"$RESOURCE/*",
|
"$RESOURCE/*",
|
||||||
"$APPDATA/*"
|
"$APPDATA/responses/*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"shell": {
|
"shell": {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { createGlobalState } from 'react-use';
|
|||||||
import { useActiveRequestId } from '../hooks/useActiveRequestId';
|
import { useActiveRequestId } from '../hooks/useActiveRequestId';
|
||||||
import { useDeleteResponse } from '../hooks/useDeleteResponse';
|
import { useDeleteResponse } from '../hooks/useDeleteResponse';
|
||||||
import { useDeleteResponses } from '../hooks/useDeleteResponses';
|
import { useDeleteResponses } from '../hooks/useDeleteResponses';
|
||||||
|
import { useLatestResponse } from '../hooks/useLatestResponse';
|
||||||
import { useResponseContentType } from '../hooks/useResponseContentType';
|
import { useResponseContentType } from '../hooks/useResponseContentType';
|
||||||
import { useResponses } from '../hooks/useResponses';
|
import { useResponses } from '../hooks/useResponses';
|
||||||
import { useResponseViewMode } from '../hooks/useResponseViewMode';
|
import { useResponseViewMode } from '../hooks/useResponseViewMode';
|
||||||
@@ -38,10 +39,11 @@ const useActiveTab = createGlobalState<string>('body');
|
|||||||
export const ResponsePane = memo(function ResponsePane({ style, className }: Props) {
|
export const ResponsePane = memo(function ResponsePane({ style, className }: Props) {
|
||||||
const [pinnedResponseId, setPinnedResponseId] = useState<string | null>(null);
|
const [pinnedResponseId, setPinnedResponseId] = useState<string | null>(null);
|
||||||
const activeRequestId = useActiveRequestId();
|
const activeRequestId = useActiveRequestId();
|
||||||
|
const latestResponse = useLatestResponse(activeRequestId);
|
||||||
const responses = useResponses(activeRequestId);
|
const responses = useResponses(activeRequestId);
|
||||||
const activeResponse: HttpResponse | null = pinnedResponseId
|
const activeResponse: HttpResponse | null = pinnedResponseId
|
||||||
? responses.find((r) => r.id === pinnedResponseId) ?? null
|
? responses.find((r) => r.id === pinnedResponseId) ?? null
|
||||||
: responses[0] ?? null;
|
: latestResponse ?? null;
|
||||||
const [viewMode, setViewMode] = useResponseViewMode(activeResponse?.requestId);
|
const [viewMode, setViewMode] = useResponseViewMode(activeResponse?.requestId);
|
||||||
const deleteResponse = useDeleteResponse(activeResponse?.id ?? null);
|
const deleteResponse = useDeleteResponse(activeResponse?.id ?? null);
|
||||||
const deleteAllResponses = useDeleteResponses(activeResponse?.requestId);
|
const deleteAllResponses = useDeleteResponses(activeResponse?.requestId);
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import { useResponses } from './useResponses';
|
|||||||
|
|
||||||
export function useLatestResponse(requestId: string | null): HttpResponse | null {
|
export function useLatestResponse(requestId: string | null): HttpResponse | null {
|
||||||
const responses = useResponses(requestId);
|
const responses = useResponses(requestId);
|
||||||
return responses[responses.length - 1] ?? null;
|
return responses[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ export function useResponseBodyText(response: HttpResponse) {
|
|||||||
initialData: null,
|
initialData: null,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (response.body) {
|
if (response.body) {
|
||||||
return String.fromCharCode.apply(null, response.body);
|
const uint8Array = Uint8Array.of(...response.body);
|
||||||
|
return new TextDecoder().decode(uint8Array);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.bodyPath) {
|
if (response.bodyPath) {
|
||||||
|
|||||||
Reference in New Issue
Block a user