import type { HttpRequest } from '@yaakapp-internal/models'; import { formatSdl } from 'format-graphql'; import { useAtom } from 'jotai'; import { useCallback, useMemo } 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 type { DropdownItem } from '../core/Dropdown'; import { Dropdown } from '../core/Dropdown'; import type { EditorProps } from '../core/Editor/Editor'; import { Editor } from '../core/Editor/LazyEditor'; import { FormattedError } from '../core/FormattedError'; import { Icon } from '../core/Icon'; import { Separator } from '../core/Separator'; import { showGraphQLDocExplorerAtom } from './graphqlAtoms'; type Props = Pick & { baseRequest: HttpRequest; onChange: (body: HttpRequest['body']) => void; request: HttpRequest; }; export function GraphQLEditor(props: Props) { // There's some weirdness with stale onChange being called when switching requests, so we'll // key on the request ID as a workaround for now. return ; } function GraphQLEditorInner({ request, onChange, baseRequest, ...extraEditorProps }: Props) { 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 [isDocOpenRecord, setGraphqlDocStateAtomValue] = useAtom(showGraphQLDocExplorerAtom); const isDocOpen = isDocOpenRecord[request.id] !== undefined; const handleChangeQuery = useCallback( (query: string) => { setCurrentBody(({ variables }) => { const newBody = { query, variables }; onChange(newBody); return newBody; }); }, [onChange, setCurrentBody], ); const handleChangeVariables = useCallback( (variables: string) => { setCurrentBody(({ query }) => { const newBody = { query, variables: variables || undefined }; onChange(newBody); return newBody; }); }, [onChange, setCurrentBody], ); const actions = useMemo( () => [
{schema === undefined ? null /* Initializing */ : ( , }, { type: 'separator' }, ] : []) satisfies DropdownItem[]), { hidden: !error, label: (

Schema introspection failed

), }); }} > View Error ), type: 'content', }, { hidden: schema == null, label: `${isDocOpen ? 'Hide' : 'Show'} Documentation`, leftSlot: , onSelect: () => { setGraphqlDocStateAtomValue((v) => ({ ...v, [request.id]: isDocOpen ? undefined : null, })); }, }, { label: 'Introspect Schema', leftSlot: , keepOpenOnSelect: true, onSelect: refetch, }, { type: 'separator', label: 'Setting' }, { label: 'Automatic Introspection', onSelect: () => { setAutoIntrospectDisabled({ ...autoIntrospectDisabled, [baseRequest.id]: !autoIntrospectDisabled?.[baseRequest.id], }); }, leftSlot: ( ), }, ]} > )}
, ], [ schema, clear, error, isDocOpen, isLoading, refetch, autoIntrospectDisabled, baseRequest.id, setGraphqlDocStateAtomValue, request.id, setAutoIntrospectDisabled, ], ); return (
Variables
); } function tryParseJson(text: string, fallback: unknown) { try { return JSON.parse(text); } catch { return fallback; } }