mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 00:58:32 +02:00
Add toggle for pretty view
This commit is contained in:
43
package-lock.json
generated
43
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"@codemirror/lang-html": "^6.4.2",
|
"@codemirror/lang-html": "^6.4.2",
|
||||||
"@codemirror/lang-javascript": "^6.1.4",
|
"@codemirror/lang-javascript": "^6.1.4",
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/lang-xml": "^6.0.2",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
"@codemirror/search": "^6.2.3",
|
"@codemirror/search": "^6.2.3",
|
||||||
"@lezer/generator": "^1.2.2",
|
"@lezer/generator": "^1.2.2",
|
||||||
@@ -497,6 +498,18 @@
|
|||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/lang-xml": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.4.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.0.0",
|
||||||
|
"@lezer/xml": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.6.0",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz",
|
||||||
@@ -1126,6 +1139,15 @@
|
|||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@motionone/animation": {
|
"node_modules/@motionone/animation": {
|
||||||
"version": "10.15.1",
|
"version": "10.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
||||||
@@ -7055,6 +7077,18 @@
|
|||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@codemirror/lang-xml": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==",
|
||||||
|
"requires": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.4.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@lezer/common": "^1.0.0",
|
||||||
|
"@lezer/xml": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@codemirror/language": {
|
"@codemirror/language": {
|
||||||
"version": "6.6.0",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz",
|
||||||
@@ -7450,6 +7484,15 @@
|
|||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@lezer/xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==",
|
||||||
|
"requires": {
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@motionone/animation": {
|
"@motionone/animation": {
|
||||||
"version": "10.15.1",
|
"version": "10.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"@codemirror/lang-html": "^6.4.2",
|
"@codemirror/lang-html": "^6.4.2",
|
||||||
"@codemirror/lang-javascript": "^6.1.4",
|
"@codemirror/lang-javascript": "^6.1.4",
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/lang-xml": "^6.0.2",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
"@codemirror/search": "^6.2.3",
|
"@codemirror/search": "^6.2.3",
|
||||||
"@lezer/generator": "^1.2.2",
|
"@lezer/generator": "^1.2.2",
|
||||||
|
|||||||
9
src-web/components/ButtonLink.tsx
Normal file
9
src-web/components/ButtonLink.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import type { LinkProps } from 'react-router-dom';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Button, ButtonProps } from './Button';
|
||||||
|
|
||||||
|
type Props = ButtonProps<typeof Link> & LinkProps;
|
||||||
|
|
||||||
|
export function ButtonLink({ ...props }: Props) {
|
||||||
|
return <Button as={Link} {...props} />;
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
rectangularSelection,
|
rectangularSelection,
|
||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { html } from '@codemirror/lang-html';
|
import { html } from '@codemirror/lang-html';
|
||||||
|
import { xml } from '@codemirror/lang-xml';
|
||||||
import { parseMixed } from '@lezer/common';
|
import { parseMixed } from '@lezer/common';
|
||||||
import { EditorState } from '@codemirror/state';
|
import { EditorState } from '@codemirror/state';
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
@@ -44,15 +45,15 @@ export const myHighlightStyle = HighlightStyle.define([
|
|||||||
{
|
{
|
||||||
tag: [t.documentMeta, t.blockComment, t.lineComment, t.docComment, t.comment],
|
tag: [t.documentMeta, t.blockComment, t.lineComment, t.docComment, t.comment],
|
||||||
color: '#757b93',
|
color: '#757b93',
|
||||||
|
fontStyle: 'italic',
|
||||||
},
|
},
|
||||||
{ tag: [t.name], color: '#4699de' },
|
{ tag: [t.name, t.tagName, t.angleBracket, t.docString], color: '#4699de' },
|
||||||
{ tag: [t.variableName], color: '#31c434' },
|
{ tag: [t.variableName], color: '#31c434' },
|
||||||
{ tag: [t.bool], color: '#e864f6' },
|
{ tag: [t.bool], color: '#e864f6' },
|
||||||
{ tag: [t.attributeName], color: '#8f68ff' },
|
{ tag: [t.attributeName], color: '#a773ff' },
|
||||||
{ tag: [t.attributeValue], color: '#ff964b' },
|
{ tag: [t.attributeValue], color: '#ff964b' },
|
||||||
{ tag: [t.string], color: '#e8b045' },
|
{ tag: [t.string], color: '#e8b045' },
|
||||||
{ tag: [t.keyword, t.meta], color: '#45e8a4' },
|
{ tag: [t.keyword, t.meta], color: '#45e8a4' },
|
||||||
{ tag: [t.comment], color: '#cec4cc', fontStyle: 'italic' },
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// export const defaultHighlightStyle = HighlightStyle.define([
|
// export const defaultHighlightStyle = HighlightStyle.define([
|
||||||
@@ -81,6 +82,8 @@ const syntaxExtensions: Record<string, { base: LanguageSupport; ext: any[] }> =
|
|||||||
'application/json': { base: json(), ext: [] },
|
'application/json': { base: json(), ext: [] },
|
||||||
'application/javascript': { base: javascript(), ext: [] },
|
'application/javascript': { base: javascript(), ext: [] },
|
||||||
'text/html': { base: html(), ext: [] },
|
'text/html': { base: html(), ext: [] },
|
||||||
|
'application/xml': { base: xml(), ext: [] },
|
||||||
|
'text/xml': { base: xml(), ext: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
export function syntaxExtension({
|
export function syntaxExtension({
|
||||||
@@ -90,7 +93,8 @@ export function syntaxExtension({
|
|||||||
contentType: string;
|
contentType: string;
|
||||||
useTemplating?: boolean;
|
useTemplating?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { base, ext } = syntaxExtensions[contentType] ?? { base: json(), ext: [] };
|
const justContentType = contentType.split(';')[0] ?? contentType;
|
||||||
|
const { base, ext } = syntaxExtensions[justContentType] ?? { base: json(), ext: [] };
|
||||||
if (!useTemplating) {
|
if (!useTemplating) {
|
||||||
return [base];
|
return [base];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ import {
|
|||||||
ArchiveIcon,
|
ArchiveIcon,
|
||||||
CameraIcon,
|
CameraIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
|
CodeIcon,
|
||||||
|
EyeOpenIcon,
|
||||||
GearIcon,
|
GearIcon,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
MoonIcon,
|
MoonIcon,
|
||||||
PaperPlaneIcon,
|
PaperPlaneIcon,
|
||||||
|
PlusCircledIcon,
|
||||||
|
PlusIcon,
|
||||||
QuestionMarkIcon,
|
QuestionMarkIcon,
|
||||||
SunIcon,
|
SunIcon,
|
||||||
TriangleDownIcon,
|
TriangleDownIcon,
|
||||||
@@ -19,17 +23,23 @@ type IconName =
|
|||||||
| 'home'
|
| 'home'
|
||||||
| 'camera'
|
| 'camera'
|
||||||
| 'gear'
|
| 'gear'
|
||||||
|
| 'eye'
|
||||||
| 'triangle-down'
|
| 'triangle-down'
|
||||||
| 'paper-plane'
|
| 'paper-plane'
|
||||||
| 'update'
|
| 'update'
|
||||||
| 'question'
|
| 'question'
|
||||||
| 'check'
|
| 'check'
|
||||||
|
| 'plus'
|
||||||
|
| 'plus-circled'
|
||||||
| 'sun'
|
| 'sun'
|
||||||
|
| 'code'
|
||||||
| 'moon';
|
| 'moon';
|
||||||
|
|
||||||
const icons: Record<IconName, NamedExoticComponent<{ className: string }>> = {
|
const icons: Record<IconName, NamedExoticComponent<{ className: string }>> = {
|
||||||
'paper-plane': PaperPlaneIcon,
|
'paper-plane': PaperPlaneIcon,
|
||||||
'triangle-down': TriangleDownIcon,
|
'triangle-down': TriangleDownIcon,
|
||||||
|
plus: PlusIcon,
|
||||||
|
'plus-circled': PlusCircledIcon,
|
||||||
archive: ArchiveIcon,
|
archive: ArchiveIcon,
|
||||||
camera: CameraIcon,
|
camera: CameraIcon,
|
||||||
check: CheckIcon,
|
check: CheckIcon,
|
||||||
@@ -39,6 +49,8 @@ const icons: Record<IconName, NamedExoticComponent<{ className: string }>> = {
|
|||||||
sun: SunIcon,
|
sun: SunIcon,
|
||||||
moon: MoonIcon,
|
moon: MoonIcon,
|
||||||
question: QuestionMarkIcon,
|
question: QuestionMarkIcon,
|
||||||
|
eye: EyeOpenIcon,
|
||||||
|
code: CodeIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IconProps {
|
export interface IconProps {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface Props {
|
|||||||
|
|
||||||
export function ResponsePane({ requestId, error }: Props) {
|
export function ResponsePane({ requestId, error }: Props) {
|
||||||
const [activeResponseId, setActiveResponseId] = useState<string | null>(null);
|
const [activeResponseId, setActiveResponseId] = useState<string | null>(null);
|
||||||
|
const [viewMode, setViewMode] = useState<'pretty' | 'raw'>('pretty');
|
||||||
const responses = useResponses(requestId);
|
const responses = useResponses(requestId);
|
||||||
const response = activeResponseId
|
const response = activeResponseId
|
||||||
? responses.data.find((r) => r.id === activeResponseId)
|
? responses.data.find((r) => r.id === activeResponseId)
|
||||||
@@ -73,15 +74,23 @@ export function ResponsePane({ requestId, error }: Props) {
|
|||||||
<>
|
<>
|
||||||
<HStack
|
<HStack
|
||||||
items="center"
|
items="center"
|
||||||
className="italic text-gray-500 text-sm w-full pointer-events-none h-10 mb-3 flex-shrink-0"
|
className="italic text-gray-500 text-sm w-full h-10 mb-3 flex-shrink-0"
|
||||||
>
|
>
|
||||||
{response.status}
|
<div>
|
||||||
{response.statusReason && ` ${response.statusReason}`}
|
{response.status}
|
||||||
•
|
{response.statusReason && ` ${response.statusReason}`}
|
||||||
{response.elapsed}ms •
|
•
|
||||||
{Math.round(response.body.length / 1000)} KB
|
{response.elapsed}ms •
|
||||||
|
{Math.round(response.body.length / 1000)} KB
|
||||||
|
</div>
|
||||||
|
<IconButton
|
||||||
|
icon={viewMode === 'pretty' ? 'eye' : 'code'}
|
||||||
|
size="sm"
|
||||||
|
className="ml-auto"
|
||||||
|
onClick={() => setViewMode((m) => (m === 'pretty' ? 'raw' : 'pretty'))}
|
||||||
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
{contentType.includes('html') ? (
|
{viewMode === 'pretty' && contentType.includes('html') ? (
|
||||||
<iframe
|
<iframe
|
||||||
title="Response preview"
|
title="Response preview"
|
||||||
srcDoc={contentForIframe}
|
srcDoc={contentForIframe}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function Sidebar({ className, activeRequestId, workspaceId, requests, ...
|
|||||||
<IconButton size="sm" icon="sun" onClick={toggleTheme} />
|
<IconButton size="sm" icon="sun" onClick={toggleTheme} />
|
||||||
<IconButton
|
<IconButton
|
||||||
size="sm"
|
size="sm"
|
||||||
icon="camera"
|
icon="plus-circled"
|
||||||
onClick={() => createRequest.mutate({ name: 'Test Request' })}
|
onClick={() => createRequest.mutate({ name: 'Test Request' })}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { Button } from '../components/Button';
|
import { ButtonLink } from '../components/ButtonLink';
|
||||||
|
|
||||||
export function Workspaces() {
|
export function Workspaces() {
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
return (
|
return (
|
||||||
<ul className="p-12">
|
<ul className="p-12">
|
||||||
{workspaces.data?.map((w) => (
|
{workspaces.data?.map((w) => (
|
||||||
<Button as={Link} key={w.id} to={`/workspaces/${w.id}`}>
|
<ButtonLink key={w.id} to={`/workspaces/${w.id}`}>
|
||||||
{w.name}
|
{w.name}
|
||||||
</Button>
|
</ButtonLink>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user