diff --git a/src-web/components/GraphQLEditor.tsx b/src-web/components/GraphQLEditor.tsx index 6a1d7851..52edbb82 100644 --- a/src-web/components/GraphQLEditor.tsx +++ b/src-web/components/GraphQLEditor.tsx @@ -1,4 +1,3 @@ -import { updateSchema } from 'cm6-graphql'; import type { EditorView } from 'codemirror'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL'; @@ -10,6 +9,7 @@ import { Editor, formatGraphQL } from './core/Editor'; import { FormattedError } from './core/FormattedError'; import { Separator } from './core/Separator'; import { useDialog } from './DialogContext'; +import { updateSchema } from 'cm6-graphql'; type Props = Pick< EditorProps, @@ -43,7 +43,13 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi }, [defaultValue]); const handleChange = useCallback( - (b: GraphQLBody) => onChange?.(JSON.stringify(b, null, 2)), + (b: GraphQLBody) => { + try { + onChange?.(JSON.stringify(b, null, 2)); + } catch (err) { + // Meh, not much we can do here + } + }, [onChange], ); @@ -53,24 +59,66 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi ); const handleChangeVariables = useCallback( - (variables: string) => { - try { - handleChange({ query, variables: JSON.parse(variables) }); - } catch (e) { - // Meh, not much we can do here - } - }, + (variables: string) => handleChange({ query, variables: JSON.parse(variables) }), [handleChange, query], ); // Refetch the schema when the URL changes useEffect(() => { if (editorViewRef.current === null) return; - updateSchema(editorViewRef.current, schema); + console.log('SET SCHEMA', schema); + updateSchema(editorViewRef.current, schema ?? undefined); }, [schema]); const dialog = useDialog(); + const actions = useMemo(() => { + const isValid = error || isLoading; + if (!isValid) { + return []; + } + + const actions: EditorProps['actions'] = [ +
+ +
+ + ), + }); + }} + > + {error ? 'Introspection Failed' : 'Introspecting'} + + , + ]; + + return actions; + }, [dialog, error, isLoading, refetch]); + return (
- -
- - ), - }); - }} - > - {error ? 'Introspection Failed' : 'Introspecting'} - - , - ] - : [] - } + actions={actions} {...extraEditorProps} />
diff --git a/src-web/hooks/useIntrospectGraphQL.ts b/src-web/hooks/useIntrospectGraphQL.ts index 12d99821..824554e6 100644 --- a/src-web/hooks/useIntrospectGraphQL.ts +++ b/src-web/hooks/useIntrospectGraphQL.ts @@ -1,6 +1,5 @@ import type { IntrospectionQuery } from 'graphql'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useLocalStorage } from 'react-use'; import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor'; import { minPromiseMillis } from '../lib/minPromiseMillis'; import type { HttpRequest } from '../lib/models'; @@ -8,6 +7,7 @@ import { getResponseBodyText } from '../lib/responseBody'; import { sendEphemeralRequest } from '../lib/sendEphemeralRequest'; import { useActiveEnvironmentId } from './useActiveEnvironmentId'; import { useDebouncedValue } from './useDebouncedValue'; +import { useKeyValue } from './useKeyValue'; const introspectionRequestBody = JSON.stringify({ query: getIntrospectionQuery(), @@ -22,9 +22,12 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) { const [refetchKey, setRefetchKey] = useState(0); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(); - const [introspection, setIntrospection] = useLocalStorage( - `introspection:${baseRequest.id}`, - ); + + const { value: introspection, set: setIntrospection } = useKeyValue({ + key: ['graphql_introspection', baseRequest.id], + fallback: null, + namespace: 'global', + }); const introspectionInterval = useRef(); @@ -40,31 +43,26 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) { const response = await minPromiseMillis(sendEphemeralRequest(args, activeEnvironmentId), 700); if (response.error) { - return Promise.reject(new Error(response.error)); + throw new Error(response.error); } const bodyText = await getResponseBodyText(response); if (response.status < 200 || response.status >= 300) { - return Promise.reject( - new Error(`Request failed with status ${response.status}.\n\n${bodyText}`), - ); + throw new Error(`Request failed with status ${response.status}.\n\n${bodyText}`); } if (bodyText === null) { - return Promise.reject(new Error('Empty body returned in response')); + throw new Error('Empty body returned in response'); } const { data } = JSON.parse(bodyText); console.log('Introspection response', data); - setIntrospection(data); + await setIntrospection(data); }; const runIntrospection = () => { fetchIntrospection() - .catch((e) => { - setIntrospection(null); - setError(e.message); - }) + .catch((e) => setError(e.message)) .finally(() => setIsLoading(false)); };