mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 09:08:32 +02:00
GraphQL query editor transformer works!
This commit is contained in:
Binary file not shown.
@@ -81,13 +81,11 @@ function FormRow({
|
|||||||
pair,
|
pair,
|
||||||
onChange,
|
onChange,
|
||||||
onDelete,
|
onDelete,
|
||||||
onFocus,
|
|
||||||
isLast,
|
isLast,
|
||||||
}: {
|
}: {
|
||||||
pair: PairWithId;
|
pair: PairWithId;
|
||||||
onChange: (pair: PairWithId) => void;
|
onChange: (pair: PairWithId) => void;
|
||||||
onDelete?: (pair: PairWithId) => void;
|
onDelete?: (pair: PairWithId) => void;
|
||||||
onFocus?: (pair: PairWithId) => void;
|
|
||||||
isLast?: boolean;
|
isLast?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -99,7 +97,6 @@ function FormRow({
|
|||||||
label="Name"
|
label="Name"
|
||||||
name="name"
|
name="name"
|
||||||
onChange={(name) => onChange({ id: pair.id, header: { name } })}
|
onChange={(name) => onChange({ id: pair.id, header: { name } })}
|
||||||
onFocus={() => onFocus?.(pair)}
|
|
||||||
placeholder="name"
|
placeholder="name"
|
||||||
useEditor={{ useTemplating: true }}
|
useEditor={{ useTemplating: true }}
|
||||||
/>
|
/>
|
||||||
@@ -110,7 +107,6 @@ function FormRow({
|
|||||||
label="Value"
|
label="Value"
|
||||||
name="value"
|
name="value"
|
||||||
onChange={(value) => onChange({ id: pair.id, header: { value } })}
|
onChange={(value) => onChange({ id: pair.id, header: { value } })}
|
||||||
onFocus={() => onFocus?.(pair)}
|
|
||||||
placeholder="value"
|
placeholder="value"
|
||||||
useEditor={{ useTemplating: true }}
|
useEditor={{ useTemplating: true }}
|
||||||
/>
|
/>
|
||||||
@@ -118,7 +114,8 @@ function FormRow({
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon="trash"
|
icon="trash"
|
||||||
onClick={() => onDelete(pair)}
|
onClick={() => onDelete(pair)}
|
||||||
className="invisible group-hover:visible"
|
tabIndex={-1}
|
||||||
|
className={classnames('opacity-0 group-hover:opacity-100')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useSendRequest } from '../hooks/useSendRequest';
|
import { useSendRequest } from '../hooks/useSendRequest';
|
||||||
import { useUpdateRequest } from '../hooks/useUpdateRequest';
|
import { useUpdateRequest } from '../hooks/useUpdateRequest';
|
||||||
import { Editor } from './core/Editor';
|
import { Editor } from './core/Editor';
|
||||||
import { HeaderEditor } from './HeaderEditor';
|
|
||||||
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||||
|
import { GraphQLEditor } from './editors/GraphQLEditor';
|
||||||
|
import { HeaderEditor } from './HeaderEditor';
|
||||||
import { UrlBar } from './UrlBar';
|
import { UrlBar } from './UrlBar';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -63,21 +65,20 @@ export function RequestPane({ fullHeight, className }: Props) {
|
|||||||
{activeRequest.bodyType === 'json' ? (
|
{activeRequest.bodyType === 'json' ? (
|
||||||
<Editor
|
<Editor
|
||||||
key={activeRequest.id}
|
key={activeRequest.id}
|
||||||
|
useTemplating
|
||||||
className="!bg-gray-50"
|
className="!bg-gray-50"
|
||||||
heightMode={fullHeight ? 'full' : 'auto'}
|
heightMode={fullHeight ? 'full' : 'auto'}
|
||||||
useTemplating
|
|
||||||
defaultValue={activeRequest.body ?? ''}
|
defaultValue={activeRequest.body ?? ''}
|
||||||
contentType="application/json"
|
contentType="application/json"
|
||||||
onChange={(body) => updateRequest.mutate({ body })}
|
onChange={(body) => updateRequest.mutate({ body })}
|
||||||
/>
|
/>
|
||||||
) : activeRequest.bodyType === 'graphql' ? (
|
) : activeRequest.bodyType === 'graphql' ? (
|
||||||
<Editor
|
<GraphQLEditor
|
||||||
key={activeRequest.id}
|
key={activeRequest.id}
|
||||||
className="!bg-gray-50"
|
|
||||||
heightMode={fullHeight ? 'full' : 'auto'}
|
|
||||||
useTemplating
|
useTemplating
|
||||||
defaultValue={activeRequest.body ?? ''}
|
className="!bg-gray-50"
|
||||||
contentType="application/graphql+json"
|
defaultValue={activeRequest?.body ?? ''}
|
||||||
|
heightMode={fullHeight ? 'full' : 'auto'}
|
||||||
onChange={(body) => updateRequest.mutate({ body })}
|
onChange={(body) => updateRequest.mutate({ body })}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { VStack } from './core/Stacks';
|
|||||||
export default function RouteError() {
|
export default function RouteError() {
|
||||||
const error = useRouteError();
|
const error = useRouteError();
|
||||||
const stringified = JSON.stringify(error);
|
const stringified = JSON.stringify(error);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const message = (error as any).message ?? stringified;
|
const message = (error as any).message ?? stringified;
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-full">
|
<div className="flex items-center justify-center h-full">
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function Workspace() {
|
|||||||
: 'grid-cols-1 grid-rows-[minmax(0,auto)_minmax(0,100%)]',
|
: 'grid-cols-1 grid-rows-[minmax(0,auto)_minmax(0,100%)]',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<RequestPane fullHeight={isH} className={classnames(!isH && 'pr-2 pb-0')} />
|
<RequestPane fullHeight={isH} className={classnames(!isH && 'pr-2')} />
|
||||||
<ResponsePane />
|
<ResponsePane />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import {
|
|||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { graphqlLanguageSupport } from 'cm6-graphql';
|
import { graphqlLanguageSupport } from 'cm6-graphql';
|
||||||
import { debouncedAutocompletionDisplay } from './autocomplete';
|
|
||||||
import { twig } from './twig/extension';
|
import { twig } from './twig/extension';
|
||||||
import { url } from './url/extension';
|
import { url } from './url/extension';
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ export const myHighlightStyle = HighlightStyle.define([
|
|||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
const syntaxExtensions: Record<string, LanguageSupport> = {
|
const syntaxExtensions: Record<string, LanguageSupport> = {
|
||||||
'application/graphql+json': graphqlLanguageSupport(),
|
'application/graphql': graphqlLanguageSupport(),
|
||||||
'application/json': json(),
|
'application/json': json(),
|
||||||
'application/javascript': javascript(),
|
'application/javascript': javascript(),
|
||||||
'text/html': html(),
|
'text/html': html(),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as T from '@radix-ui/react-tabs';
|
import * as T from '@radix-ui/react-tabs';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import type { ReactElement, ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button } from '../Button';
|
import { Button } from '../Button';
|
||||||
import type { DropdownMenuRadioItem, DropdownMenuRadioProps } from '../Dropdown';
|
import type { DropdownMenuRadioItem, DropdownMenuRadioProps } from '../Dropdown';
|
||||||
@@ -81,7 +81,7 @@ export function Tabs({ defaultValue, label, children, tabs, className, tabListCl
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{t.options.items.find((i) => i.value === t.options?.value)?.label ?? ''}
|
{t.options.items.find((i) => i.value === t.options?.value)?.label ?? ''}
|
||||||
<Icon icon="triangleDown" className="-mr-1.5" />
|
<Icon icon="triangleDown" className="-mr-1.5 opacity-40" />
|
||||||
</Button>
|
</Button>
|
||||||
</T.Trigger>
|
</T.Trigger>
|
||||||
);
|
);
|
||||||
|
|||||||
32
src-web/components/editors/GraphQLEditor.tsx
Normal file
32
src-web/components/editors/GraphQLEditor.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import type { EditorProps } from '../core/Editor';
|
||||||
|
import { Editor } from '../core/Editor';
|
||||||
|
|
||||||
|
type Props = Pick<
|
||||||
|
EditorProps,
|
||||||
|
'heightMode' | 'onChange' | 'defaultValue' | 'className' | 'useTemplating'
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function GraphQLEditor({ defaultValue, onChange, ...props }: Props) {
|
||||||
|
const { query } = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const { query } = JSON.parse(defaultValue ?? '{}');
|
||||||
|
return { query };
|
||||||
|
} catch (err) {
|
||||||
|
return { query: 'failed to parse' };
|
||||||
|
}
|
||||||
|
}, [defaultValue]);
|
||||||
|
|
||||||
|
const handleChange = (query: string) => {
|
||||||
|
onChange?.(JSON.stringify({ query }, null, 2));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Editor
|
||||||
|
defaultValue={query ?? ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
contentType="application/graphql"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,11 +11,11 @@ const darkTheme: AppTheme = {
|
|||||||
blackPoint: 0.2,
|
blackPoint: 0.2,
|
||||||
colors: {
|
colors: {
|
||||||
gray: '#6b5b98',
|
gray: '#6b5b98',
|
||||||
red: '#ee3b3b',
|
red: '#ff417b',
|
||||||
orange: '#ff9411',
|
orange: '#ff9411',
|
||||||
yellow: '#dcc73b',
|
yellow: '#e8d13f',
|
||||||
green: '#44cb44',
|
green: '#43e76f',
|
||||||
blue: '#2e91ff',
|
blue: '#219dff',
|
||||||
pink: '#f670f6',
|
pink: '#f670f6',
|
||||||
violet: '#b176ff',
|
violet: '#b176ff',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user