import type { EditorView } from '@codemirror/view'; import type { HttpRequest } from '@yaakapp-internal/models'; import { updateSchema } from 'cm6-graphql'; import { formatSdl } from 'format-graphql'; import { useEffect, useMemo, useRef } from 'react'; import { useLocalStorage } from 'react-use'; import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL'; import { useStateWithDeps } from '../hooks/useStateWithDeps'; import { showDialog } from '../lib/dialog'; import { Banner } from './core/Banner'; import { Button } from './core/Button'; import { Dropdown } from './core/Dropdown'; import type { EditorProps } from './core/Editor/Editor'; import { Editor } from './core/Editor/Editor'; import { FormattedError } from './core/FormattedError'; import { Icon } from './core/Icon'; import { Separator } from './core/Separator'; type Props = Pick & { baseRequest: HttpRequest; onChange: (body: HttpRequest['body']) => void; request: HttpRequest; }; export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorProps }: Props) { const editorViewRef = useRef(null); const [autoIntrospectDisabled, setAutoIntrospectDisabled] = useLocalStorage< Record >('graphQLAutoIntrospectDisabled', {}); const { schema, isLoading, error, refetch, clear } = useIntrospectGraphQL(baseRequest, { disabled: autoIntrospectDisabled?.[baseRequest.id], }); const [currentBody, setCurrentBody] = useStateWithDeps<{ query: string; variables: string | undefined; }>(() => { // Migrate text bodies to GraphQL format // NOTE: This is how GraphQL used to be stored if ('text' in request.body) { const b = tryParseJson(request.body.text, {}); const variables = JSON.stringify(b.variables || undefined, null, 2); return { query: b.query ?? '', variables }; } return { query: request.body.query ?? '', variables: request.body.variables ?? '' }; }, [extraEditorProps.forceUpdateKey]); const handleChangeQuery = (query: string) => { const newBody = { query, variables: currentBody.variables || undefined }; setCurrentBody(newBody); onChange(newBody); }; const handleChangeVariables = (variables: string) => { const newBody = { query: currentBody.query, variables: variables || undefined }; setCurrentBody(newBody); onChange(newBody); }; // Refetch the schema when the URL changes useEffect(() => { if (editorViewRef.current == null) return; updateSchema(editorViewRef.current, schema ?? undefined); }, [schema]); const actions = useMemo( () => [
{schema === undefined ? null /* Initializing */ : (

Schema introspection failed

), }); }} > View Error ), type: 'content', }, { label: 'Refetch', leftSlot: , onSelect: refetch, }, { label: 'Clear', onSelect: clear, hidden: !schema, color: 'danger', leftSlot: , }, { type: 'separator', label: 'Setting' }, { label: 'Automatic Introspection', onSelect: () => { setAutoIntrospectDisabled({ ...autoIntrospectDisabled, [baseRequest.id]: !autoIntrospectDisabled?.[baseRequest.id], }); }, leftSlot: ( ), }, ]} > )} , ], [ isLoading, refetch, error, autoIntrospectDisabled, baseRequest.id, clear, schema, setAutoIntrospectDisabled, ], ); return (
Variables
); } function tryParseJson(text: string, fallback: unknown) { try { return JSON.parse(text); // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (err) { return fallback; } }