From c609d0ff0cd2ec4ba0ecdcec121cb6d72d642c3f Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 21 Jul 2025 14:17:36 -0700 Subject: [PATCH] Fix GraphQL schema getting nuked on codemirror language refresh --- src-web/components/core/Editor/Editor.tsx | 20 +++++++++++++------- src-web/components/core/Editor/extensions.ts | 5 ++++- src-web/components/graphql/GraphQLEditor.tsx | 10 ++-------- src-web/hooks/useFilterResponse.ts | 4 ++++ 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index d1db2c59..989d6dac 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -12,9 +12,10 @@ import { settingsAtom } from '@yaakapp-internal/models'; import type { EditorLanguage, TemplateFunction } from '@yaakapp-internal/plugins'; import { parseTemplate } from '@yaakapp-internal/templates'; import classNames from 'classnames'; +import type { GraphQLSchema } from 'graphql'; import { useAtomValue } from 'jotai'; import { md5 } from 'js-md5'; -import type { MutableRefObject, ReactNode } from 'react'; +import type { ReactNode, RefObject } from 'react'; import { Children, cloneElement, @@ -77,6 +78,7 @@ export interface EditorProps { hideGutter?: boolean; id?: string; language?: EditorLanguage | 'pairs' | 'url'; + graphQLSchema?: GraphQLSchema | null; onBlur?: () => void; onChange?: (value: string) => void; onFocus?: () => void; @@ -115,6 +117,7 @@ export const Editor = forwardRef(function E format, heightMode, hideGutter, + graphQLSchema, language, onBlur, onChange, @@ -374,6 +377,7 @@ export const Editor = forwardRef(function E onClickVariable, onClickMissingVariable, onClickPathParameter, + graphQLSchema: graphQLSchema ?? null, }); view.dispatch({ effects: languageCompartment.reconfigure(ext) }); }, [ @@ -386,6 +390,7 @@ export const Editor = forwardRef(function E onClickPathParameter, completionOptions, useTemplating, + graphQLSchema, ]); // Initialize the editor when ref mounts @@ -408,6 +413,7 @@ export const Editor = forwardRef(function E onClickVariable, onClickMissingVariable, onClickPathParameter, + graphQLSchema: graphQLSchema ?? null, }); const extensions = [ languageCompartment.of(langExt), @@ -595,12 +601,12 @@ function getExtensions({ }: Pick & { stateKey: EditorProps['stateKey']; container: HTMLDivElement | null; - onChange: MutableRefObject; - onPaste: MutableRefObject; - onPasteOverwrite: MutableRefObject; - onFocus: MutableRefObject; - onBlur: MutableRefObject; - onKeyDown: MutableRefObject; + onChange: RefObject; + onPaste: RefObject; + onPasteOverwrite: RefObject; + onFocus: RefObject; + onBlur: RefObject; + onKeyDown: RefObject; }) { // TODO: Ensure tooltips render inside the dialog if we are in one. const parent = diff --git a/src-web/components/core/Editor/extensions.ts b/src-web/components/core/Editor/extensions.ts index 9bbbc8b3..df29933a 100644 --- a/src-web/components/core/Editor/extensions.ts +++ b/src-web/components/core/Editor/extensions.ts @@ -37,6 +37,7 @@ import { import { tags as t } from '@lezer/highlight'; import type { EnvironmentVariable } from '@yaakapp-internal/models'; import { graphql } from 'cm6-graphql'; +import type { GraphQLSchema } from 'graphql'; import { activeRequestIdAtom } from '../../../hooks/useActiveRequestId'; import { jotaiStore } from '../../../lib/jotai'; import { renderMarkdown } from '../../../lib/markdown'; @@ -106,6 +107,7 @@ export function getLanguageExtension({ onClickMissingVariable, onClickPathParameter, completionOptions, + graphQLSchema, }: { useTemplating: boolean; environmentVariables: EnvironmentVariable[]; @@ -113,6 +115,7 @@ export function getLanguageExtension({ onClickMissingVariable: (name: string, tagValue: string, startPos: number) => void; onClickPathParameter: (name: string) => void; completionOptions: TwigCompletionOption[]; + graphQLSchema: GraphQLSchema | null; } & Pick) { const extraExtensions: Extension[] = []; @@ -128,7 +131,7 @@ export function getLanguageExtension({ // GraphQL is a special exception if (language === 'graphql') { return [ - graphql(undefined, { + graphql(graphQLSchema ?? undefined, { async onCompletionInfoRender(gqlCompletionItem): Promise { if (!gqlCompletionItem.documentation) return null; const innerHTML = await renderMarkdown(gqlCompletionItem.documentation); diff --git a/src-web/components/graphql/GraphQLEditor.tsx b/src-web/components/graphql/GraphQLEditor.tsx index 89b36a36..c0c19786 100644 --- a/src-web/components/graphql/GraphQLEditor.tsx +++ b/src-web/components/graphql/GraphQLEditor.tsx @@ -1,10 +1,9 @@ import type { EditorView } from '@codemirror/view'; import type { HttpRequest } from '@yaakapp-internal/models'; -import { updateSchema } from 'cm6-graphql'; import { formatSdl } from 'format-graphql'; import { useAtom } from 'jotai'; -import { useEffect, useMemo, useRef } from 'react'; +import { useMemo, useRef } from 'react'; import { useLocalStorage } from 'react-use'; import { useIntrospectGraphQL } from '../../hooks/useIntrospectGraphQL'; import { useStateWithDeps } from '../../hooks/useStateWithDeps'; @@ -63,12 +62,6 @@ export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorPr onChange(newBody); }; - // Refetch the schema when the URL changes - useEffect(() => { - if (editorViewRef.current == null) return; - updateSchema(editorViewRef.current, schema ?? undefined); - }, [schema]); - const actions = useMemo( () => [
@@ -201,6 +194,7 @@ export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorPr