@@ -12,13 +12,14 @@ import { ToggleJsonIcon } from "@src/react-app/components/icons/ToggleJsonIcon";
12
12
import { trpc } from "@src/react-app/trpc" ;
13
13
import type { RenderOptions } from "@src/render" ;
14
14
import { sample } from "@stoplight/json-schema-sampler" ;
15
- import type { UseMutationResult , UseQueryResult } from "@tanstack/react-query" ;
15
+
16
16
import { fullFormats } from "ajv-formats/dist/formats" ;
17
- import React , { useEffect , useRef , useState } from "react" ;
17
+ import React , { useRef , useState } from "react" ;
18
18
import { type Control , useForm , useFormState } from "react-hook-form" ;
19
19
import getSize from "string-byte-length" ;
20
20
import SuperJson from "superjson" ;
21
21
import { z } from "zod" ;
22
+ import { useAsyncDuration } from "../../hooks/useAsyncDuration" ;
22
23
import { AutoFillIcon } from "../../icons/AutoFillIcon" ;
23
24
import JSONEditor from "../JSONEditor" ;
24
25
import { ErrorDisplay as ErrorComponent } from "./Error" ;
@@ -57,6 +58,16 @@ function isTrpcError(error: unknown): error is TRPCErrorType {
57
58
58
59
export const ROOT_VALS_PROPERTY_NAME = "vals" ;
59
60
61
+ // Recurse down the path to get the function to call
62
+ function getUtilsOrProcedure ( base : any , procedure : ParsedProcedure ) {
63
+ let cur = base ;
64
+ for ( const p of procedure . pathFromRootRouter ) {
65
+ //@ts -ignore
66
+ cur = cur [ p ] ;
67
+ }
68
+ return cur ;
69
+ }
70
+
60
71
export function ProcedureForm ( {
61
72
procedure,
62
73
options,
@@ -68,54 +79,12 @@ export function ProcedureForm({
68
79
} ) {
69
80
// null => request was never sent
70
81
// undefined => request successful but nothing returned from procedure
71
- const [ mutationResponse , setMutationResponse ] = useState < any > ( null ) ;
72
- const [ queryEnabled , setQueryEnabled ] = useState < boolean > ( false ) ;
73
- const [ queryInput , setQueryInput ] = useState < any > ( null ) ;
82
+ const [ response , setResponse ] = useState < any > ( null ) ;
83
+ const { duration, loading, measureAsyncDuration } = useAsyncDuration ( ) ;
74
84
const formRef = useRef < HTMLFormElement | null > ( null ) ;
75
- const context = trpc . useContext ( ) ;
76
- const [ startTime , setStartTime ] = useState < number | undefined > ( ) ;
77
- const [ opDuration , setOpDuration ] = useState < number | undefined > ( ) ;
78
-
79
- function getProcedure ( ) {
80
- let cur : typeof trpc | ( typeof trpc ) [ string ] = trpc ;
81
- for ( const p of procedure . pathFromRootRouter ) {
82
- // TODO - Maybe figure out these typings?
83
- //@ts -ignore
84
- cur = cur [ p ] ;
85
- }
86
- return cur ;
87
- }
88
-
89
- const query = ( ( ) => {
90
- const router = getProcedure ( ) ;
91
- //@ts -ignore
92
- return router . useQuery ( queryInput , {
93
- enabled : queryEnabled ,
94
- initialData : null ,
95
- retry : false ,
96
- refetchOnWindowFocus : false ,
97
- } ) ;
98
- } ) ( ) as UseQueryResult < any > ;
99
-
100
- function invalidateQuery ( input : any ) {
101
- let cur : any = context ;
102
- for ( const p of procedure . pathFromRootRouter ) {
103
- cur = cur [ p ] ;
104
- }
105
- cur . invalidate ( input ) ;
106
- }
107
-
108
- const mutation = ( ( ) => {
109
- const router = getProcedure ( ) ;
110
- //@ts -ignore
111
- return router . useMutation ( {
112
- retry : false ,
113
- onSuccess : ( data : unknown ) => {
114
- if ( startTime ) setOpDuration ( Date . now ( ) - startTime ) ;
115
- setStartTime ( undefined ) ;
116
- } ,
117
- } ) ;
118
- } ) ( ) as UseMutationResult < any > ;
85
+ const utils = trpc . useUtils ( ) ;
86
+ const { mutateAsync } = getUtilsOrProcedure ( trpc , procedure ) . useMutation ( ) ;
87
+ const fetchFunction = getUtilsOrProcedure ( utils , procedure ) . fetch ;
119
88
120
89
const {
121
90
control,
@@ -131,74 +100,25 @@ export function ProcedureForm({
131
100
[ ROOT_VALS_PROPERTY_NAME ] : defaultFormValuesForNode ( procedure . node ) ,
132
101
} ,
133
102
} ) ;
134
- function onSubmit ( data : { [ ROOT_VALS_PROPERTY_NAME ] : any } ) {
103
+ async function onSubmit ( data : { [ ROOT_VALS_PROPERTY_NAME ] : any } ) {
135
104
let newData : any ;
136
105
if ( options . transformer === "superjson" ) {
137
106
newData = SuperJson . serialize ( data [ ROOT_VALS_PROPERTY_NAME ] ) ;
138
107
} else {
139
108
newData = { ...data [ ROOT_VALS_PROPERTY_NAME ] } ;
140
109
}
141
- if ( procedure . procedureType === "query" ) {
142
- setQueryInput ( newData ) ;
143
- setQueryEnabled ( true ) ;
144
- invalidateQuery ( newData ) ;
145
- } else {
146
- setStartTime ( Date . now ( ) ) ;
147
- mutation . mutateAsync ( newData ) . then ( setMutationResponse ) . catch ( ) ;
148
- }
110
+ const apiCaller =
111
+ procedure . procedureType === "query" ? fetchFunction : mutateAsync ;
112
+ const result = await measureAsyncDuration (
113
+ async ( ) => await apiCaller ( newData ) ,
114
+ ) ;
115
+ setResponse ( result ) ;
149
116
}
150
117
151
- // I've seen stuff online saying form reset should happen in useEffect hook only
152
- // not really sure though, gonna just leave it for now
153
- const [ shouldReset , setShouldReset ] = useState ( false ) ;
154
- useEffect ( ( ) => {
155
- if ( shouldReset ) {
156
- resetForm (
157
- { [ ROOT_VALS_PROPERTY_NAME ] : defaultFormValuesForNode ( procedure . node ) } ,
158
- {
159
- keepValues : false ,
160
- keepDirtyValues : false ,
161
- keepDefaultValues : false ,
162
- } ,
163
- ) ;
164
- setShouldReset ( false ) ;
165
- }
166
- } , [ shouldReset , setShouldReset , resetForm , defaultFormValuesForNode ] ) ;
167
- function reset ( ) {
168
- setShouldReset ( true ) ;
169
- setQueryEnabled ( false ) ;
170
- }
171
-
172
- let data : any ;
173
- if ( procedure . procedureType === "query" ) {
174
- data = query . data ?? null ;
175
- } else {
176
- data = mutationResponse ;
177
- }
178
-
179
- // Get raw size before deserialization
180
- const size = getSize ( JSON . stringify ( data ) ) ;
181
- if ( options . transformer === "superjson" && data ) {
182
- data = SuperJson . deserialize ( data ) ;
183
- }
184
- const error =
185
- procedure . procedureType === "query" ? query . error : mutation . error ;
186
-
187
- // Fixes the timing for queries, not ideal but works
188
- useEffect ( ( ) => {
189
- if ( query . fetchStatus === "fetching" ) {
190
- setStartTime ( Date . now ( ) ) ;
191
- }
192
- if ( query . fetchStatus === "idle" ) {
193
- setOpDuration ( Date . now ( ) - startTime ) ;
194
- }
195
- } , [ query . fetchStatus ] ) ;
196
-
197
118
const fieldName = procedure . node . path . join ( "." ) ;
198
119
199
120
const [ useRawInput , setUseRawInput ] = useState ( false ) ;
200
121
function toggleRawInput ( ) {
201
- console . log ( getValues ( ) ) ;
202
122
setUseRawInput ( ! useRawInput ) ;
203
123
}
204
124
@@ -226,7 +146,7 @@ export function ProcedureForm({
226
146
title = "Input"
227
147
topRightElement = {
228
148
< div className = "flex space-x-1" >
229
- < XButton control = { control } reset = { reset } />
149
+ < XButton control = { control } reset = { resetForm } />
230
150
< div className = "h-6 w-6" >
231
151
< button
232
152
type = "button"
@@ -269,25 +189,22 @@ export function ProcedureForm({
269
189
< ProcedureFormButton
270
190
text = { `Execute ${ name } ` }
271
191
colorScheme = { "neutral" }
272
- loading = { query . fetchStatus === "fetching" || mutation . isPending }
192
+ loading = { loading }
273
193
/>
274
194
</ FormSection >
275
195
</ div >
276
196
</ form >
277
197
< div className = "flex flex-col space-y-4" >
278
- { data && (
279
- < Response size = { size } time = { opDuration } >
280
- { data }
281
- </ Response >
282
- ) }
283
- { ! data && data !== null && (
284
- < Response > Successful request but no data was returned</ Response >
285
- ) }
286
- { error &&
287
- ( isTrpcError ( error ) ? (
288
- < ErrorComponent error = { error } />
198
+ { response &&
199
+ ( isTrpcError ( response ) ? (
200
+ < ErrorComponent error = { response } />
289
201
) : (
290
- < Response > { error } </ Response >
202
+ < Response
203
+ time = { duration ?? undefined }
204
+ size = { getSize ( JSON . stringify ( response ) ) }
205
+ >
206
+ { response }
207
+ </ Response >
291
208
) ) }
292
209
</ div >
293
210
</ CollapsableSection >
0 commit comments