fix http response load when filter (#251)

This commit is contained in:
Hao Xiang
2025-09-17 04:01:00 +08:00
committed by GitHub
parent 8c3ed60579
commit fec64b5c02
11 changed files with 97 additions and 102 deletions

View File

@@ -13,7 +13,7 @@ interface Props {
}
export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Props) {
const rawTextBody = useResponseBodyText(response);
const rawTextBody = useResponseBodyText({ responseId: response.id, filter: null });
const contentType = getContentTypeFromHeaders(response.headers);
const language = languageFromContentType(contentType, rawTextBody.data ?? '');
@@ -24,7 +24,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
if (language === 'html' && pretty) {
return <WebPageViewer response={response} />;
} else if (rawTextBody.data == null) {
return <EmptyStateText>Empty response</EmptyStateText>
return <EmptyStateText>Empty response</EmptyStateText>;
} else {
return (
<TextViewer

View File

@@ -3,8 +3,8 @@ import type { ReactNode } from 'react';
import { useCallback, useMemo } from 'react';
import { createGlobalState } from 'react-use';
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
import { useFilterResponse } from '../../hooks/useFilterResponse';
import { useFormatText } from '../../hooks/useFormatText';
import { useResponseBodyText } from '../../hooks/useResponseBodyText';
import type { EditorProps } from '../core/Editor/Editor';
import { Editor } from '../core/Editor/Editor';
import { hyperlink } from '../core/Editor/hyperlink/extension';
@@ -36,7 +36,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
);
const isSearching = filterText != null;
const filteredResponse = useFilterResponse({ filter: debouncedFilterText ?? '', responseId });
const filteredResponse = useResponseBodyText({ responseId, filter: debouncedFilterText ?? null });
const toggleSearch = useCallback(() => {
if (isSearching) {
@@ -58,7 +58,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
<div key="input" className="w-full !opacity-100">
<Input
key={requestId}
validate={!(filteredResponse.error || filteredResponse.data?.error)}
validate={!filteredResponse.error}
hideLabel
autoFocus
containerClassName="bg-surface"
@@ -91,7 +91,6 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
}, [
canFilter,
filterText,
filteredResponse.data?.error,
filteredResponse.error,
filteredResponse.isPending,
isSearching,
@@ -112,7 +111,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
if (filteredResponse.error) {
body = '';
} else {
body = filteredResponse.data?.content != null ? filteredResponse.data.content : '';
body = filteredResponse.data != null ? filteredResponse.data : '';
}
} else {
body = formattedBody;

View File

@@ -1,31 +0,0 @@
import { useQuery } from '@tanstack/react-query';
import type { FilterResponse } from '@yaakapp-internal/plugins';
import { invokeCmd } from '../lib/tauri';
export function useFilterResponse({
responseId,
filter,
}: {
responseId: string | null;
filter: string;
}) {
return useQuery({
queryKey: ['filter_response', responseId, filter],
queryFn: async () => {
if (filter === '') {
return null;
}
const result = (await invokeCmd('cmd_filter_response', {
responseId,
filter,
})) as FilterResponse;
if (result.error) {
console.log("Failed to filter response:", result.error);
}
return result;
},
});
}

View File

@@ -1,12 +0,0 @@
import { useQuery } from '@tanstack/react-query';
import type { HttpResponse } from '@yaakapp-internal/models';
import { getResponseBodyBlob } from '../lib/responseBody';
export function useResponseBodyBlob(response: HttpResponse) {
return useQuery<Uint8Array | null>({
enabled: response != null,
queryKey: ['response-body-binary', response?.updatedAt],
initialData: null,
queryFn: () => getResponseBodyBlob(response),
}).data;
}

View File

@@ -1,11 +1,15 @@
import { useQuery } from '@tanstack/react-query';
import type { HttpResponse } from '@yaakapp-internal/models';
import { getResponseBodyText } from '../lib/responseBody';
export function useResponseBodyText(response: HttpResponse) {
export function useResponseBodyText({
responseId,
filter,
}: {
responseId: string;
filter: string | null;
}) {
return useQuery({
placeholderData: (prev) => prev, // Keep previous data on refetch
queryKey: ['response-body-text', response.id, response.updatedAt, response.contentLength],
queryFn: () => getResponseBodyText(response),
queryKey: ['response_body_text', responseId, filter ?? ''],
queryFn: () => getResponseBodyText({ responseId, filter }),
});
}

View File

@@ -1,23 +1,25 @@
import { readFile } from '@tauri-apps/plugin-fs';
import type { HttpResponse } from '@yaakapp-internal/models';
import type { FilterResponse } from '@yaakapp-internal/plugins';
import type { ServerSentEvent } from '@yaakapp-internal/sse';
import { getCharsetFromContentType } from './model_util';
import { invokeCmd } from './tauri';
export async function getResponseBodyText(response: HttpResponse): Promise<string | null> {
if (!response.bodyPath) {
return null;
export async function getResponseBodyText({
responseId,
filter,
}: {
responseId: string;
filter: string | null;
}): Promise<string | null> {
const result = await invokeCmd<FilterResponse>('cmd_http_response_body', {
responseId,
filter,
});
if (result.error) {
throw new Error(result.error);
}
const bytes = await readFile(response.bodyPath);
const charset = getCharsetFromContentType(response.headers);
return new TextDecoder(charset ?? 'utf-8', { fatal: false }).decode(bytes);
}
export async function getResponseBodyBlob(response: HttpResponse): Promise<Uint8Array | null> {
if (!response.bodyPath) return null;
return readFile(response.bodyPath);
return result.content;
}
export async function getResponseBodyEventSource(

View File

@@ -2,30 +2,29 @@ import type { InvokeArgs } from '@tauri-apps/api/core';
import { invoke } from '@tauri-apps/api/core';
type TauriCmd =
| 'cmd_get_themes'
| 'cmd_call_http_authentication_action'
| 'cmd_call_grpc_request_action'
| 'cmd_call_http_authentication_action'
| 'cmd_call_http_request_action'
| 'cmd_check_for_updates'
| 'cmd_create_grpc_request'
| 'cmd_curl_to_request'
| 'cmd_decrypt_template'
| 'cmd_secure_template'
| 'cmd_delete_all_grpc_connections'
| 'cmd_delete_all_http_responses'
| 'cmd_delete_send_history'
| 'cmd_dismiss_notification'
| 'cmd_export_data'
| 'cmd_filter_response'
| 'cmd_format_json'
| 'cmd_get_http_authentication_config'
| 'cmd_get_http_authentication_summaries'
| 'cmd_get_sse_events'
| 'cmd_get_themes'
| 'cmd_get_workspace_meta'
| 'cmd_grpc_go'
| 'cmd_grpc_reflect'
| 'cmd_grpc_request_actions'
| 'cmd_http_request_actions'
| 'cmd_http_response_body'
| 'cmd_import_data'
| 'cmd_install_plugin'
| 'cmd_metadata'
@@ -35,6 +34,7 @@ type TauriCmd =
| 'cmd_reload_plugins'
| 'cmd_render_template'
| 'cmd_save_response'
| 'cmd_secure_template'
| 'cmd_send_ephemeral_request'
| 'cmd_send_http_request'
| 'cmd_show_workspace_key'