mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-21 08:21:19 +02:00
Persist introspection queries and also improve
This commit is contained in:
@@ -24,8 +24,7 @@ interface GraphQLBody {
|
|||||||
|
|
||||||
export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEditorProps }: Props) {
|
export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEditorProps }: Props) {
|
||||||
const editorViewRef = useRef<EditorView>(null);
|
const editorViewRef = useRef<EditorView>(null);
|
||||||
const introspection = useIntrospectGraphQL(baseRequest);
|
const { schema, isLoading, error } = useIntrospectGraphQL(baseRequest);
|
||||||
|
|
||||||
const { query, variables } = useMemo<GraphQLBody>(() => {
|
const { query, variables } = useMemo<GraphQLBody>(() => {
|
||||||
if (defaultValue === undefined) {
|
if (defaultValue === undefined) {
|
||||||
return { query: '', variables: {} };
|
return { query: '', variables: {} };
|
||||||
@@ -65,8 +64,8 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi
|
|||||||
// Refetch the schema when the URL changes
|
// Refetch the schema when the URL changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editorViewRef.current === null) return;
|
if (editorViewRef.current === null) return;
|
||||||
updateSchema(editorViewRef.current, introspection.data);
|
updateSchema(editorViewRef.current, schema);
|
||||||
}, [introspection.data]);
|
}, [schema]);
|
||||||
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
|
|
||||||
@@ -81,22 +80,20 @@ export function GraphQLEditor({ defaultValue, onChange, baseRequest, ...extraEdi
|
|||||||
placeholder="..."
|
placeholder="..."
|
||||||
ref={editorViewRef}
|
ref={editorViewRef}
|
||||||
actions={
|
actions={
|
||||||
(introspection.error || introspection.isLoading) && (
|
(error || isLoading) && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
color={introspection.error ? 'danger' : 'gray'}
|
color={error ? 'danger' : 'gray'}
|
||||||
isLoading={introspection.isLoading}
|
isLoading={isLoading}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dialog.show({
|
dialog.show({
|
||||||
title: 'Introspection Failed',
|
title: 'Introspection Failed',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
render: () => (
|
render: () => <div className="whitespace-pre-wrap">{error}</div>,
|
||||||
<div className="whitespace-pre-wrap">{introspection.error?.message}</div>
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{introspection.error ? 'Introspection Failed' : 'Introspecting'}
|
{error ? 'Introspection Failed' : 'Introspecting'}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import type { IntrospectionQuery } from 'graphql';
|
||||||
import type { GraphQLSchema } from 'graphql';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useLocalStorage } from 'react-use';
|
||||||
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
import { buildClientSchema, getIntrospectionQuery } from '../components/core/Editor';
|
||||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||||
import type { HttpRequest } from '../lib/models';
|
import type { HttpRequest } from '../lib/models';
|
||||||
@@ -13,18 +14,23 @@ const introspectionRequestBody = JSON.stringify({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
||||||
// Debounce the URL because it can change rapidly, and we don't
|
// Debounce the request because it can change rapidly and we don't
|
||||||
// want to send so many requests.
|
// want to send so too many requests.
|
||||||
const request = useDebouncedValue(baseRequest);
|
const request = useDebouncedValue(baseRequest);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
const [error, setError] = useState<string>();
|
||||||
|
const [introspection, setIntrospection] = useLocalStorage<IntrospectionQuery>(
|
||||||
|
`introspection:${baseRequest.id}`,
|
||||||
|
);
|
||||||
|
|
||||||
return useQuery<GraphQLSchema, Error>({
|
const introspectionInterval = useRef<NodeJS.Timeout>();
|
||||||
queryKey: ['introspectGraphQL', { url: request.url, method: request.method }],
|
|
||||||
refetchInterval: 1000 * 60, // Refetch every minute
|
useEffect(() => {
|
||||||
queryFn: async () => {
|
const fetchIntrospection = async () => {
|
||||||
const response = await minPromiseMillis(
|
setIsLoading(true);
|
||||||
sendEphemeralRequest({ ...baseRequest, body: introspectionRequestBody }),
|
setError(undefined);
|
||||||
700,
|
const args = { ...baseRequest, body: introspectionRequestBody };
|
||||||
);
|
const response = await minPromiseMillis(sendEphemeralRequest(args), 700);
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
return Promise.reject(new Error(response.error));
|
return Promise.reject(new Error(response.error));
|
||||||
@@ -42,7 +48,27 @@ export function useIntrospectGraphQL(baseRequest: HttpRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { data } = JSON.parse(body);
|
const { data } = JSON.parse(body);
|
||||||
return buildClientSchema(data);
|
setIntrospection(data);
|
||||||
},
|
};
|
||||||
});
|
|
||||||
|
const runIntrospection = () => {
|
||||||
|
fetchIntrospection()
|
||||||
|
.catch((e) => setError(e.message))
|
||||||
|
.finally(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do it again on an interval
|
||||||
|
clearInterval(introspectionInterval.current);
|
||||||
|
introspectionInterval.current = setInterval(runIntrospection, 1000 * 60);
|
||||||
|
runIntrospection(); // Run immediately
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [request.id, request.method]);
|
||||||
|
|
||||||
|
const schema = useMemo(
|
||||||
|
() => (introspection ? buildClientSchema(introspection) : undefined),
|
||||||
|
[introspection],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { schema, isLoading, error };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ const darkTheme: AppTheme = {
|
|||||||
appearance: 'dark',
|
appearance: 'dark',
|
||||||
layers: {
|
layers: {
|
||||||
root: {
|
root: {
|
||||||
blackPoint: 0.2,
|
blackPoint: 0.09,
|
||||||
colors: {
|
colors: {
|
||||||
gray: '#6b5b98',
|
gray: '#9b8ebe',
|
||||||
red: '#ff417b',
|
red: '#ff417b',
|
||||||
orange: '#fd9014',
|
orange: '#fd9014',
|
||||||
yellow: '#e8d13f',
|
yellow: '#e8d13f',
|
||||||
|
|||||||
Reference in New Issue
Block a user