mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-27 20:01:10 +01:00
Run oxfmt across repo, add format script and docs
Add .oxfmtignore to skip generated bindings and wasm-pack output. Add npm format script, update DEVELOPMENT.md for Vite+ toolchain, and format all non-generated files with oxfmt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
bodyPath?: string;
|
||||
@@ -13,7 +13,7 @@ export function AudioViewer({ bodyPath, data }: Props) {
|
||||
if (bodyPath) {
|
||||
setSrc(convertFileSrc(bodyPath));
|
||||
} else if (data) {
|
||||
const blob = new Blob([new Uint8Array(data)], { type: 'audio/mpeg' });
|
||||
const blob = new Blob([new Uint8Array(data)], { type: "audio/mpeg" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
setSrc(url);
|
||||
return () => URL.revokeObjectURL(url);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import { useSaveResponse } from '../../hooks/useSaveResponse';
|
||||
import { getContentTypeFromHeaders } from '../../lib/model_util';
|
||||
import { Banner } from '../core/Banner';
|
||||
import { Button } from '../core/Button';
|
||||
import { InlineCode } from '../core/InlineCode';
|
||||
import { LoadingIcon } from '../core/LoadingIcon';
|
||||
import { EmptyStateText } from '../EmptyStateText';
|
||||
import type { HttpResponse } from "@yaakapp-internal/models";
|
||||
import { useSaveResponse } from "../../hooks/useSaveResponse";
|
||||
import { getContentTypeFromHeaders } from "../../lib/model_util";
|
||||
import { Banner } from "../core/Banner";
|
||||
import { Button } from "../core/Button";
|
||||
import { InlineCode } from "../core/InlineCode";
|
||||
import { LoadingIcon } from "../core/LoadingIcon";
|
||||
import { EmptyStateText } from "../EmptyStateText";
|
||||
|
||||
interface Props {
|
||||
response: HttpResponse;
|
||||
@@ -13,10 +13,10 @@ interface Props {
|
||||
|
||||
export function BinaryViewer({ response }: Props) {
|
||||
const saveResponse = useSaveResponse(response);
|
||||
const contentType = getContentTypeFromHeaders(response.headers) ?? 'unknown';
|
||||
const contentType = getContentTypeFromHeaders(response.headers) ?? "unknown";
|
||||
|
||||
// Wait until the response has been fully-downloaded
|
||||
if (response.state !== 'closed') {
|
||||
if (response.state !== "closed") {
|
||||
return (
|
||||
<EmptyStateText>
|
||||
<LoadingIcon size="sm" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
import Papa from 'papaparse';
|
||||
import { useMemo } from 'react';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '../core/Table';
|
||||
import classNames from "classnames";
|
||||
import Papa from "papaparse";
|
||||
import { useMemo } from "react";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "../core/Table";
|
||||
|
||||
interface Props {
|
||||
text: string | null;
|
||||
@@ -26,7 +26,7 @@ export function CsvViewerInner({ text, className }: { text: string | null; class
|
||||
|
||||
return (
|
||||
<div className="overflow-auto h-full">
|
||||
<Table className={classNames(className, 'text-sm')}>
|
||||
<Table className={classNames(className, "text-sm")}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{parsed.meta.fields?.map((field) => (
|
||||
@@ -39,7 +39,7 @@ export function CsvViewerInner({ text, className }: { text: string | null; class
|
||||
// oxlint-disable-next-line react/no-array-index-key
|
||||
<TableRow key={i}>
|
||||
{parsed.meta.fields?.map((key) => (
|
||||
<TableCell key={key}>{row[key] ?? ''}</TableCell>
|
||||
<TableCell key={key}>{row[key] ?? ""}</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import type { ServerSentEvent } from '@yaakapp-internal/sse';
|
||||
import classNames from 'classnames';
|
||||
import { Fragment, useMemo, useState } from 'react';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import { useResponseBodyEventSource } from '../../hooks/useResponseBodyEventSource';
|
||||
import { isJSON } from '../../lib/contentType';
|
||||
import { Button } from '../core/Button';
|
||||
import type { EditorProps } from '../core/Editor/Editor';
|
||||
import { Editor } from '../core/Editor/LazyEditor';
|
||||
import { EventDetailHeader, EventViewer } from '../core/EventViewer';
|
||||
import { EventViewerRow } from '../core/EventViewerRow';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { InlineCode } from '../core/InlineCode';
|
||||
import { HStack, VStack } from '../core/Stacks';
|
||||
import type { HttpResponse } from "@yaakapp-internal/models";
|
||||
import type { ServerSentEvent } from "@yaakapp-internal/sse";
|
||||
import classNames from "classnames";
|
||||
import { Fragment, useMemo, useState } from "react";
|
||||
import { useFormatText } from "../../hooks/useFormatText";
|
||||
import { useResponseBodyEventSource } from "../../hooks/useResponseBodyEventSource";
|
||||
import { isJSON } from "../../lib/contentType";
|
||||
import { Button } from "../core/Button";
|
||||
import type { EditorProps } from "../core/Editor/Editor";
|
||||
import { Editor } from "../core/Editor/LazyEditor";
|
||||
import { EventDetailHeader, EventViewer } from "../core/EventViewer";
|
||||
import { EventViewerRow } from "../core/EventViewerRow";
|
||||
import { Icon } from "../core/Icon";
|
||||
import { InlineCode } from "../core/InlineCode";
|
||||
import { HStack, VStack } from "../core/Stacks";
|
||||
|
||||
interface Props {
|
||||
response: HttpResponse;
|
||||
@@ -85,9 +85,9 @@ function EventDetail({
|
||||
setShowingLarge: (v: boolean) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const language = useMemo<'text' | 'json'>(() => {
|
||||
if (!event?.data) return 'text';
|
||||
return isJSON(event?.data) ? 'json' : 'text';
|
||||
const language = useMemo<"text" | "json">(() => {
|
||||
if (!event?.data) return "text";
|
||||
return isJSON(event?.data) ? "json" : "text";
|
||||
}, [event?.data]);
|
||||
|
||||
return (
|
||||
@@ -125,7 +125,7 @@ function EventDetail({
|
||||
);
|
||||
}
|
||||
|
||||
function FormattedEditor({ text, language }: { text: string; language: EditorProps['language'] }) {
|
||||
function FormattedEditor({ text, language }: { text: string; language: EditorProps["language"] }) {
|
||||
const formatted = useFormatText({ text, language, pretty: true });
|
||||
if (formatted == null) return null;
|
||||
return <Editor readOnly defaultValue={formatted} language={language} stateKey={null} />;
|
||||
@@ -144,11 +144,11 @@ function EventLabels({
|
||||
}) {
|
||||
return (
|
||||
<HStack space={1.5} alignItems="center" className={className}>
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
<InlineCode className={classNames("py-0", isActive && "bg-text-subtlest text-text")}>
|
||||
{event.id ?? index}
|
||||
</InlineCode>
|
||||
{event.eventType && (
|
||||
<InlineCode className={classNames('py-0', isActive && 'bg-text-subtlest text-text')}>
|
||||
<InlineCode className={classNames("py-0", isActive && "bg-text-subtlest text-text")}>
|
||||
{event.eventType}
|
||||
</InlineCode>
|
||||
)}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useResponseBodyText } from '../../hooks/useResponseBodyText';
|
||||
import { languageFromContentType } from '../../lib/contentType';
|
||||
import { getContentTypeFromHeaders } from '../../lib/model_util';
|
||||
import type { EditorProps } from '../core/Editor/Editor';
|
||||
import { EmptyStateText } from '../EmptyStateText';
|
||||
import { TextViewer } from './TextViewer';
|
||||
import { WebPageViewer } from './WebPageViewer';
|
||||
import type { HttpResponse } from "@yaakapp-internal/models";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useResponseBodyText } from "../../hooks/useResponseBodyText";
|
||||
import { languageFromContentType } from "../../lib/contentType";
|
||||
import { getContentTypeFromHeaders } from "../../lib/model_util";
|
||||
import type { EditorProps } from "../core/Editor/Editor";
|
||||
import { EmptyStateText } from "../EmptyStateText";
|
||||
import { TextViewer } from "./TextViewer";
|
||||
import { WebPageViewer } from "./WebPageViewer";
|
||||
|
||||
interface Props {
|
||||
response: HttpResponse;
|
||||
@@ -17,14 +17,14 @@ interface Props {
|
||||
export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Props) {
|
||||
const rawTextBody = useResponseBodyText({ response, filter: null });
|
||||
const contentType = getContentTypeFromHeaders(response.headers);
|
||||
const language = languageFromContentType(contentType, rawTextBody.data ?? '');
|
||||
const language = languageFromContentType(contentType, rawTextBody.data ?? "");
|
||||
|
||||
if (rawTextBody.isLoading || response.state === 'initialized') {
|
||||
if (rawTextBody.isLoading || response.state === "initialized") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (language === 'html' && pretty) {
|
||||
return <WebPageViewer html={rawTextBody.data ?? ''} baseUrl={response.url} />;
|
||||
if (language === "html" && pretty) {
|
||||
return <WebPageViewer html={rawTextBody.data ?? ""} baseUrl={response.url} />;
|
||||
}
|
||||
if (rawTextBody.data == null) {
|
||||
return <EmptyStateText>Empty response</EmptyStateText>;
|
||||
@@ -43,7 +43,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
interface HttpTextViewerProps {
|
||||
response: HttpResponse;
|
||||
text: string;
|
||||
language: EditorProps['language'];
|
||||
language: EditorProps["language"];
|
||||
pretty: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import classNames from 'classnames';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import classNames from "classnames";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type Props = { className?: string } & (
|
||||
| {
|
||||
@@ -13,14 +13,14 @@ type Props = { className?: string } & (
|
||||
|
||||
export function ImageViewer({ className, ...props }: Props) {
|
||||
const [src, setSrc] = useState<string>();
|
||||
const bodyPath = 'bodyPath' in props ? props.bodyPath : null;
|
||||
const data = 'data' in props ? props.data : null;
|
||||
const bodyPath = "bodyPath" in props ? props.bodyPath : null;
|
||||
const data = "data" in props ? props.data : null;
|
||||
|
||||
useEffect(() => {
|
||||
if (bodyPath != null) {
|
||||
setSrc(convertFileSrc(bodyPath));
|
||||
} else if (data != null) {
|
||||
const blob = new Blob([data], { type: 'image/png' });
|
||||
const blob = new Blob([data], { type: "image/png" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
setSrc(url);
|
||||
return () => URL.revokeObjectURL(url);
|
||||
@@ -33,7 +33,7 @@ export function ImageViewer({ className, ...props }: Props) {
|
||||
<img
|
||||
src={src}
|
||||
alt="Response preview"
|
||||
className={classNames(className, 'max-w-full max-h-full')}
|
||||
className={classNames(className, "max-w-full max-h-full")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import classNames from 'classnames';
|
||||
import { JsonAttributeTree } from '../core/JsonAttributeTree';
|
||||
import classNames from "classnames";
|
||||
import { JsonAttributeTree } from "../core/JsonAttributeTree";
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
@@ -15,7 +15,7 @@ export function JsonViewer({ text, className }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(className, 'overflow-x-auto h-full')}>
|
||||
<div className={classNames(className, "overflow-x-auto h-full")}>
|
||||
<JsonAttributeTree attrValue={parsed} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { type MultipartPart, parseMultipart } from '@mjackson/multipart-parser';
|
||||
import { lazy, Suspense, useMemo } from 'react';
|
||||
import { languageFromContentType } from '../../lib/contentType';
|
||||
import { Banner } from '../core/Banner';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { LoadingIcon } from '../core/LoadingIcon';
|
||||
import { TabContent, Tabs } from '../core/Tabs/Tabs';
|
||||
import { AudioViewer } from './AudioViewer';
|
||||
import { CsvViewer } from './CsvViewer';
|
||||
import { ImageViewer } from './ImageViewer';
|
||||
import { SvgViewer } from './SvgViewer';
|
||||
import { TextViewer } from './TextViewer';
|
||||
import { VideoViewer } from './VideoViewer';
|
||||
import { WebPageViewer } from './WebPageViewer';
|
||||
import { type MultipartPart, parseMultipart } from "@mjackson/multipart-parser";
|
||||
import { lazy, Suspense, useMemo } from "react";
|
||||
import { languageFromContentType } from "../../lib/contentType";
|
||||
import { Banner } from "../core/Banner";
|
||||
import { Icon } from "../core/Icon";
|
||||
import { LoadingIcon } from "../core/LoadingIcon";
|
||||
import { TabContent, Tabs } from "../core/Tabs/Tabs";
|
||||
import { AudioViewer } from "./AudioViewer";
|
||||
import { CsvViewer } from "./CsvViewer";
|
||||
import { ImageViewer } from "./ImageViewer";
|
||||
import { SvgViewer } from "./SvgViewer";
|
||||
import { TextViewer } from "./TextViewer";
|
||||
import { VideoViewer } from "./VideoViewer";
|
||||
import { WebPageViewer } from "./WebPageViewer";
|
||||
|
||||
const PdfViewer = lazy(() => import('./PdfViewer').then((m) => ({ default: m.PdfViewer })));
|
||||
const PdfViewer = lazy(() => import("./PdfViewer").then((m) => ({ default: m.PdfViewer })));
|
||||
|
||||
interface Props {
|
||||
data: Uint8Array;
|
||||
@@ -21,7 +21,7 @@ interface Props {
|
||||
idPrefix?: string;
|
||||
}
|
||||
|
||||
export function MultipartViewer({ data, boundary, idPrefix = 'multipart' }: Props) {
|
||||
export function MultipartViewer({ data, boundary, idPrefix = "multipart" }: Props) {
|
||||
const parseResult = useMemo(() => {
|
||||
try {
|
||||
const maxFileSize = 1024 * 1024 * 10; // 10MB
|
||||
@@ -58,10 +58,10 @@ export function MultipartViewer({ data, boundary, idPrefix = 'multipart' }: Prop
|
||||
layout="horizontal"
|
||||
tabListClassName="border-r border-r-border -ml-3"
|
||||
tabs={parts.map((part, i) => ({
|
||||
label: part.name ?? '',
|
||||
label: part.name ?? "",
|
||||
value: tabValue(part, i),
|
||||
rightSlot:
|
||||
part.filename && part.headers.contentType.mediaType?.startsWith('image/') ? (
|
||||
part.filename && part.headers.contentType.mediaType?.startsWith("image/") ? (
|
||||
<div className="h-5 w-5 overflow-auto flex items-center justify-end">
|
||||
<ImageViewer
|
||||
data={part.arrayBuffer}
|
||||
@@ -89,7 +89,7 @@ export function MultipartViewer({ data, boundary, idPrefix = 'multipart' }: Prop
|
||||
|
||||
function Part({ part }: { part: MultipartPart }) {
|
||||
const mimeType = part.headers.contentType.mediaType ?? null;
|
||||
const contentTypeHeader = part.headers.get('content-type');
|
||||
const contentTypeHeader = part.headers.get("content-type");
|
||||
|
||||
const { uint8Array, content, detectedLanguage } = useMemo(() => {
|
||||
const uint8Array = new Uint8Array(part.arrayBuffer);
|
||||
@@ -118,7 +118,7 @@ function Part({ part }: { part: MultipartPart }) {
|
||||
return <CsvViewer text={content} className="bg-primary h-10 w-10" />;
|
||||
}
|
||||
|
||||
if (mimeType?.match(/^text\/html/i) || detectedLanguage === 'html') {
|
||||
if (mimeType?.match(/^text\/html/i) || detectedLanguage === "html") {
|
||||
return <WebPageViewer html={content} />;
|
||||
}
|
||||
|
||||
@@ -134,5 +134,5 @@ function Part({ part }: { part: MultipartPart }) {
|
||||
}
|
||||
|
||||
function tabValue(part: MultipartPart, i: number) {
|
||||
return `${part.name ?? ''}::${i}`;
|
||||
return `${part.name ?? ""}::${i}`;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import 'react-pdf/dist/Page/TextLayer.css';
|
||||
import 'react-pdf/dist/Page/AnnotationLayer.css';
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import './PdfViewer.css';
|
||||
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Document, Page } from 'react-pdf';
|
||||
import { useContainerSize } from '../../hooks/useContainerQuery';
|
||||
import { fireAndForget } from '../../lib/fireAndForget';
|
||||
import "react-pdf/dist/Page/TextLayer.css";
|
||||
import "react-pdf/dist/Page/AnnotationLayer.css";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import "./PdfViewer.css";
|
||||
import type { PDFDocumentProxy } from "pdfjs-dist";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Document, Page } from "react-pdf";
|
||||
import { useContainerSize } from "../../hooks/useContainerQuery";
|
||||
import { fireAndForget } from "../../lib/fireAndForget";
|
||||
|
||||
fireAndForget(import('react-pdf').then(({ pdfjs }) => {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
'pdfjs-dist/build/pdf.worker.min.mjs',
|
||||
import.meta.url,
|
||||
).toString();
|
||||
}));
|
||||
fireAndForget(
|
||||
import("react-pdf").then(({ pdfjs }) => {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
"pdfjs-dist/build/pdf.worker.min.mjs",
|
||||
import.meta.url,
|
||||
).toString();
|
||||
}),
|
||||
);
|
||||
|
||||
interface Props {
|
||||
bodyPath?: string;
|
||||
@@ -21,8 +23,8 @@ interface Props {
|
||||
}
|
||||
|
||||
const options = {
|
||||
cMapUrl: '/cmaps/',
|
||||
standardFontDataUrl: '/standard_fonts/',
|
||||
cMapUrl: "/cmaps/",
|
||||
standardFontDataUrl: "/standard_fonts/",
|
||||
};
|
||||
|
||||
export function PdfViewer({ bodyPath, data }: Props) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
@@ -13,7 +13,7 @@ export function SvgViewer({ text, className }: Props) {
|
||||
return setSrc(null);
|
||||
}
|
||||
|
||||
const blob = new Blob([text], { type: 'image/svg+xml;charset=utf-8' });
|
||||
const blob = new Blob([text], { type: "image/svg+xml;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
setSrc(url);
|
||||
|
||||
@@ -25,6 +25,6 @@ export function SvgViewer({ text, className }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<img src={src} alt="Response preview" className={className ?? 'max-w-full max-h-full pb-2'} />
|
||||
<img src={src} alt="Response preview" className={className ?? "max-w-full max-h-full pb-2"} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import classNames from 'classnames';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { createGlobalState } from 'react-use';
|
||||
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import type { EditorProps } from '../core/Editor/Editor';
|
||||
import { hyperlink } from '../core/Editor/hyperlink/extension';
|
||||
import { Editor } from '../core/Editor/LazyEditor';
|
||||
import { IconButton } from '../core/IconButton';
|
||||
import { Input } from '../core/Input';
|
||||
import classNames from "classnames";
|
||||
import type { ReactNode } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { createGlobalState } from "react-use";
|
||||
import { useDebouncedValue } from "../../hooks/useDebouncedValue";
|
||||
import { useFormatText } from "../../hooks/useFormatText";
|
||||
import type { EditorProps } from "../core/Editor/Editor";
|
||||
import { hyperlink } from "../core/Editor/hyperlink/extension";
|
||||
import { Editor } from "../core/Editor/LazyEditor";
|
||||
import { IconButton } from "../core/IconButton";
|
||||
import { Input } from "../core/Input";
|
||||
|
||||
const extraExtensions = [hyperlink];
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
language: EditorProps['language'];
|
||||
language: EditorProps["language"];
|
||||
stateKey: string | null;
|
||||
pretty?: boolean;
|
||||
className?: string;
|
||||
@@ -49,11 +49,11 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
|
||||
if (isSearching) {
|
||||
setFilterText(null);
|
||||
} else {
|
||||
setFilterText('');
|
||||
setFilterText("");
|
||||
}
|
||||
}, [isSearching, setFilterText]);
|
||||
|
||||
const canFilter = onFilter && (language === 'json' || language === 'xml' || language === 'html');
|
||||
const canFilter = onFilter && (language === "json" || language === "xml" || language === "html");
|
||||
|
||||
const actions = useMemo<ReactNode[]>(() => {
|
||||
const nodes: ReactNode[] = [];
|
||||
@@ -64,17 +64,17 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
|
||||
nodes.push(
|
||||
<div key="input" className="w-full !opacity-100">
|
||||
<Input
|
||||
key={stateKey ?? 'filter'}
|
||||
key={stateKey ?? "filter"}
|
||||
validate={!filteredResponse.error}
|
||||
hideLabel
|
||||
autoFocus
|
||||
containerClassName="bg-surface"
|
||||
size="sm"
|
||||
placeholder={language === 'json' ? 'JSONPath expression' : 'XPath expression'}
|
||||
placeholder={language === "json" ? "JSONPath expression" : "XPath expression"}
|
||||
label="Filter expression"
|
||||
name="filter"
|
||||
defaultValue={filterText}
|
||||
onKeyDown={(e) => e.key === 'Escape' && toggleSearch()}
|
||||
onKeyDown={(e) => e.key === "Escape" && toggleSearch()}
|
||||
onChange={setFilterText}
|
||||
stateKey={stateKey ? `filter.${stateKey}` : null}
|
||||
/>
|
||||
@@ -87,10 +87,10 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
|
||||
key="icon"
|
||||
size="sm"
|
||||
isLoading={filteredResponse.isPending}
|
||||
icon={isSearching ? 'x' : 'filter'}
|
||||
title={isSearching ? 'Close filter' : 'Filter response'}
|
||||
icon={isSearching ? "x" : "filter"}
|
||||
title={isSearching ? "Close filter" : "Filter response"}
|
||||
onClick={toggleSearch}
|
||||
className={classNames('border !border-border-subtle', isSearching && '!opacity-100')}
|
||||
className={classNames("border !border-border-subtle", isSearching && "!opacity-100")}
|
||||
/>,
|
||||
);
|
||||
|
||||
@@ -115,18 +115,18 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
|
||||
let body: string;
|
||||
if (isSearching && filterText?.length > 0) {
|
||||
if (filteredResponse.error) {
|
||||
body = '';
|
||||
body = "";
|
||||
} else {
|
||||
body = filteredResponse.data != null ? filteredResponse.data : '';
|
||||
body = filteredResponse.data != null ? filteredResponse.data : "";
|
||||
}
|
||||
} else {
|
||||
body = formattedBody;
|
||||
}
|
||||
|
||||
// Decode unicode sequences in the text to readable characters
|
||||
if (language === 'json' && pretty) {
|
||||
if (language === "json" && pretty) {
|
||||
body = decodeUnicodeLiterals(body);
|
||||
body = body.replace(/\\\//g, '/'); // Hide unnecessary escaping of '/' by some older frameworks
|
||||
body = body.replace(/\\\//g, "/"); // Hide unnecessary escaping of '/' by some older frameworks
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
bodyPath?: string;
|
||||
@@ -13,7 +13,7 @@ export function VideoViewer({ bodyPath, data }: Props) {
|
||||
if (bodyPath) {
|
||||
setSrc(convertFileSrc(bodyPath));
|
||||
} else if (data) {
|
||||
const blob = new Blob([new Uint8Array(data)], { type: 'video/mp4' });
|
||||
const blob = new Blob([new Uint8Array(data)], { type: "video/mp4" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
setSrc(url);
|
||||
return () => URL.revokeObjectURL(url);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo } from "react";
|
||||
|
||||
interface Props {
|
||||
html: string;
|
||||
@@ -7,7 +7,7 @@ interface Props {
|
||||
|
||||
export function WebPageViewer({ html, baseUrl }: Props) {
|
||||
const contentForIframe: string | undefined = useMemo(() => {
|
||||
if (baseUrl && html.includes('<head>')) {
|
||||
if (baseUrl && html.includes("<head>")) {
|
||||
return html.replace(/<head>/gi, `<head><base href="${baseUrl}"/>`);
|
||||
}
|
||||
return html;
|
||||
@@ -16,7 +16,7 @@ export function WebPageViewer({ html, baseUrl }: Props) {
|
||||
return (
|
||||
<div className="h-full pb-3">
|
||||
<iframe
|
||||
key={html ? 'has-body' : 'no-body'}
|
||||
key={html ? "has-body" : "no-body"}
|
||||
title="Yaak response preview"
|
||||
srcDoc={contentForIframe}
|
||||
sandbox="allow-scripts allow-forms"
|
||||
|
||||
Reference in New Issue
Block a user