From 8c58838726eb2eec43e2fe1ac1ee85023a0c28be Mon Sep 17 00:00:00 2001 From: Suriya Date: Fri, 22 May 2026 11:36:39 +0530 Subject: [PATCH] graphqlix --- src/components/EndpointCard.jsx | 116 ++++- src/components/TopicView.jsx | 57 ++- src/data/graphqlMeta.js | 873 ++++++++++++++++++++++++++++++++ 3 files changed, 1016 insertions(+), 30 deletions(-) create mode 100644 src/data/graphqlMeta.js diff --git a/src/components/EndpointCard.jsx b/src/components/EndpointCard.jsx index 3a2e30b..0367bea 100644 --- a/src/components/EndpointCard.jsx +++ b/src/components/EndpointCard.jsx @@ -1,8 +1,9 @@ -import { useMemo, useState } from 'react' +import { useMemo, useState, useEffect } from 'react' import { Play, Copy, Check, CheckCircle2, AlertCircle, Server, FileJson, Loader2 } from 'lucide-react' import { highlightJSON } from '../lib/highlight' +import { normalizeAndGetMeta, getGraphQLKey } from '../data/graphqlMeta' function safeDecode(v) { try { return decodeURIComponent(v) } catch { return v } @@ -20,8 +21,17 @@ function parseUrl(url) { return { path, params } } -export default function EndpointCard({ endpoint, baseUrl, onSend, result, loading }) { - const { path, params: parsedParams } = useMemo(() => parseUrl(endpoint.url), [endpoint.url]) +export default function EndpointCard({ endpoint, baseUrl, isLegacy, onSend, result, loading }) { + const gqlKey = useMemo(() => { + return isLegacy ? getGraphQLKey(endpoint.name) : null + }, [endpoint.name, isLegacy]) + + const meta = useMemo(() => { + return gqlKey ? normalizeAndGetMeta(endpoint.name) : null + }, [endpoint.name, gqlKey]) + + const { path: originalPath, params: parsedParams } = useMemo(() => parseUrl(endpoint.url), [endpoint.url]) + const path = isLegacy && gqlKey ? `/api/rest/${gqlKey}` : originalPath const paramDefs = endpoint.params || parsedParams const [values, setValues] = useState(() => @@ -30,6 +40,28 @@ export default function EndpointCard({ endpoint, baseUrl, onSend, result, loadin const [copied, setCopied] = useState(false) const [urlCopied, setUrlCopied] = useState(false) + const [queryText, setQueryText] = useState(() => meta?.query || '') + const [variablesText, setVariablesText] = useState(() => meta?.variables || '{}') + + // Reset and sync state when metadata changes + useEffect(() => { + setQueryText(meta?.query || '') + setVariablesText(meta?.variables || '{}') + + if (meta?.variables) { + try { + const parsed = JSON.parse(meta.variables) + setValues(v => { + const next = { ...v } + Object.keys(next).forEach(k => { + if (parsed[k] !== undefined) next[k] = String(parsed[k]) + }) + return next + }) + } catch (err) {} + } + }, [meta]) + const composedUrl = useMemo(() => { if (paramDefs.length === 0) return baseUrl + path const qs = paramDefs @@ -38,7 +70,31 @@ export default function EndpointCard({ endpoint, baseUrl, onSend, result, loadin return `${baseUrl}${path}?${qs}` }, [path, paramDefs, values, baseUrl]) - const handleSend = () => onSend(endpoint, composedUrl) + const handleSend = () => { + const useGraphql = endpoint.useGraphql || gqlKey === 'getinvoiceinsight' || gqlKey === 'getinvoices' + if (isLegacy && meta && (endpoint.method !== 'GET' || useGraphql)) { + const graphqlUrl = `${baseUrl}/v1/graphql` + let parsedVars = {} + try { + parsedVars = variablesText?.trim() ? JSON.parse(variablesText) : {} + } catch (err) {} + + const overrideOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-hasura-admin-secret': 'nearle-admin-secret' + }, + body: JSON.stringify({ + query: queryText, + variables: parsedVars + }) + } + onSend(endpoint, graphqlUrl, overrideOptions) + } else { + onSend(endpoint, composedUrl) + } + } const copyResponse = async () => { if (!result || result.kind !== 'response') return @@ -116,9 +172,17 @@ export default function EndpointCard({ endpoint, baseUrl, onSend, result, loadin className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500/20 focus:border-brand-500 transition-all shadow-sm text-slate-700" value={values[p.name] ?? ''} placeholder={`Enter ${p.name}...`} - onChange={(e) => - setValues((v) => ({ ...v, [p.name]: e.target.value })) - } + onChange={(e) => { + const newVal = e.target.value + setValues((v) => ({ ...v, [p.name]: newVal })) + if (isLegacy && meta) { + try { + const parsed = JSON.parse(variablesText || '{}') + const updatedValue = isNaN(newVal) || newVal.trim() === '' ? newVal : Number(newVal) + setVariablesText(JSON.stringify({ ...parsed, [p.name]: updatedValue }, null, 2)) + } catch (err) {} + } + }} /> ))} @@ -140,7 +204,43 @@ export default function EndpointCard({ endpoint, baseUrl, onSend, result, loadin {/* Payload body or composed URL preview */} - {endpoint.body ? ( + {isLegacy && meta ? ( +
+
+
+ GraphQL Query +
+