-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathinteractive-editor.tsx
More file actions
122 lines (112 loc) · 3.62 KB
/
interactive-editor.tsx
File metadata and controls
122 lines (112 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"use client"
import { graphql } from "graphql"
import { useRef, useState } from "react"
import { getVariableToType } from "@/components/interactive-code-block/get-variable-to-type"
import { QueryEditor } from "@/components/interactive-code-block/query-editor"
import { ResultViewer } from "@/components/interactive-code-block/result-viewer"
import { VariableEditor } from "@/components/interactive-code-block/variable-editor"
import { CodeBlockLabel } from "@/components/pre/code-block-label"
import { HowItWorksListItem } from "./how-it-works-list-item"
import { PlayButton } from "./play-button"
import {
INITIAL_QUERY_TEXT,
INITIAL_RESULTS_TEXT,
projectsSchema as schema,
} from "./schema"
export default function InteractiveEditor() {
const [query, setQuery] = useState(INITIAL_QUERY_TEXT)
const [results, setResults] = useState(INITIAL_RESULTS_TEXT)
const [variableTypes, setVariableTypes] = useState<Record<string, string>>({})
const [variables, setVariables] = useState("")
const editorQueryId = useRef(0)
async function runQuery(
options: { manual: boolean },
source: string = query,
) {
editorQueryId.current++
const queryID = editorQueryId.current
try {
const result = await graphql({
schema,
source,
variableValues: JSON.parse(variables || "{}"),
})
let resultToSerialize: any = result
if (result.errors) {
if (!options.manual) {
// if the query was ran on edit, we display errors on the left side
// so we can just return instead of showing the resulting error
return
}
// Convert errors to serializable format
const serializedErrors = result.errors.map(error => ({
message: error.message,
locations: error.locations,
path: error.path,
}))
// Replace errors with serialized version for JSON.stringify
resultToSerialize = { ...result, errors: serializedErrors }
}
if (queryID === editorQueryId.current) {
setResults(JSON.stringify(resultToSerialize, null, 2))
}
} catch (error) {
if (queryID === editorQueryId.current) {
setResults(JSON.stringify(error, null, 2))
}
}
}
const editor = (
<QueryEditor
value={query}
schema={schema}
onEdit={newQuery => {
setQuery(newQuery)
runQuery({ manual: false }, newQuery)
}}
runQuery={() => {
setVariableTypes(getVariableToType(schema, query))
runQuery({ manual: true })
}}
/>
)
return (
<>
<HowItWorksListItem
text="Ask for what you want"
icon={
<PlayButton
onClick={() => {
void runQuery({ manual: true })
}}
/>
}
code={
Object.keys(variableTypes).length > 0 ? (
<div className="flex flex-col">
{editor}
<div className="flex flex-col border-neu-200 dark:border-neu-50">
<CodeBlockLabel
text="Variables"
className="border-b border-neu-200 bg-transparent dark:border-neu-50"
/>
<VariableEditor
value={variables}
variableToType={variableTypes}
onEdit={setVariables}
onRunQuery={() => void runQuery({ manual: false })}
/>
</div>
</div>
) : (
editor
)
}
/>
<HowItWorksListItem
text="Get predictable results"
code={<ResultViewer value={results} vainlyExtractData />}
/>
</>
)
}