mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-17 23:13:51 +01:00
Custom JSON formatter that works with template syntax (#128)
This commit is contained in:
@@ -61,7 +61,7 @@ export interface EditorProps {
|
||||
onKeyDown?: (e: KeyboardEvent) => void;
|
||||
singleLine?: boolean;
|
||||
wrapLines?: boolean;
|
||||
format?: (v: string) => string;
|
||||
format?: (v: string) => Promise<string>;
|
||||
autocomplete?: GenericCompletionConfig;
|
||||
autocompleteVariables?: boolean;
|
||||
extraExtensions?: Extension[];
|
||||
@@ -387,10 +387,10 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
icon="magic_wand"
|
||||
variant="border"
|
||||
className={classNames(actionClassName)}
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
if (cm.current === null) return;
|
||||
const { doc } = cm.current.view.state;
|
||||
const formatted = format(doc.toString());
|
||||
const formatted = await format(doc.toString());
|
||||
// Update editor and blur because the cursor will reset anyway
|
||||
cm.current.view.dispatch({
|
||||
changes: { from: 0, to: doc.length, insert: formatted },
|
||||
|
||||
@@ -4,10 +4,11 @@ import type { ServerSentEvent } from '@yaakapp-internal/sse';
|
||||
import classNames from 'classnames';
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { Fragment, useMemo, useRef, useState } from 'react';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import { useResponseBodyEventSource } from '../../hooks/useResponseBodyEventSource';
|
||||
import { isJSON } from '../../lib/contentType';
|
||||
import { tryFormatJson } from '../../lib/formatters';
|
||||
import { Button } from '../core/Button';
|
||||
import type { EditorProps } from '../core/Editor';
|
||||
import { Editor } from '../core/Editor';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { InlineCode } from '../core/InlineCode';
|
||||
@@ -95,11 +96,7 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
</div>
|
||||
</VStack>
|
||||
) : (
|
||||
<Editor
|
||||
readOnly
|
||||
defaultValue={tryFormatJson(activeEvent.data)}
|
||||
language={language}
|
||||
/>
|
||||
<FormattedEditor language={language} text={activeEvent.data} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,6 +107,12 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
function FormattedEditor({ text, language }: { text: string; language: EditorProps['language'] }) {
|
||||
const formatted = useFormatText({ text, language, pretty: true });
|
||||
if (formatted.data == null) return null;
|
||||
return <Editor readOnly defaultValue={formatted.data} language={language} />;
|
||||
}
|
||||
|
||||
function EventStreamEventsVirtual({
|
||||
events,
|
||||
activeEventIndex,
|
||||
|
||||
@@ -31,7 +31,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
}
|
||||
|
||||
if (language === 'html' && pretty) {
|
||||
return <WebPageViewer response={response} />;
|
||||
return <WebPageViewer response={response}/>;
|
||||
} else {
|
||||
return (
|
||||
<TextViewer
|
||||
|
||||
@@ -5,8 +5,8 @@ import { createGlobalState } from 'react-use';
|
||||
import { useCopy } from '../../hooks/useCopy';
|
||||
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
|
||||
import { useFilterResponse } from '../../hooks/useFilterResponse';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import { useToggle } from '../../hooks/useToggle';
|
||||
import { tryFormatJson, tryFormatXml } from '../../lib/formatters';
|
||||
import { CopyButton } from '../CopyButton';
|
||||
import { Banner } from '../core/Banner';
|
||||
import { Button } from '../core/Button';
|
||||
@@ -117,6 +117,8 @@ export function TextViewer({
|
||||
toggleSearch,
|
||||
]);
|
||||
|
||||
const formattedBody = useFormatText({ text, language, pretty });
|
||||
|
||||
if (!showLargeResponse && text.length > LARGE_RESPONSE_BYTES) {
|
||||
return (
|
||||
<Banner color="primary" className="h-full flex flex-col gap-3">
|
||||
@@ -140,12 +142,9 @@ export function TextViewer({
|
||||
);
|
||||
}
|
||||
|
||||
const formattedBody =
|
||||
pretty && language === 'json'
|
||||
? tryFormatJson(text)
|
||||
: pretty && (language === 'xml' || language === 'html')
|
||||
? tryFormatXml(text)
|
||||
: text;
|
||||
if (formattedBody.isFetching) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let body;
|
||||
if (isSearching && filterText?.length > 0) {
|
||||
@@ -155,7 +154,7 @@ export function TextViewer({
|
||||
body = filteredResponse.data != null ? filteredResponse.data : '';
|
||||
}
|
||||
} else {
|
||||
body = formattedBody;
|
||||
body = formattedBody.data;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user