@@ -25,6 +25,7 @@ import {
25
25
PlayIcon ,
26
26
} from "lucide-react" ;
27
27
import Link from "next/link" ;
28
+ import type { OpenAPIV3 } from "openapi-types" ;
28
29
import { useEffect , useMemo , useState } from "react" ;
29
30
import { type UseFormReturn , useForm } from "react-hook-form" ;
30
31
import { z } from "zod" ;
@@ -118,8 +119,10 @@ function modifyParametersForPlayground(_parameters: BlueprintParameter[]) {
118
119
name : "chainId" ,
119
120
in : "path" ,
120
121
required : true ,
121
- description : "Chain ID" ,
122
- type : "integer" ,
122
+ schema : {
123
+ type : "integer" ,
124
+ description : "Chain ID of the blockchain" ,
125
+ } ,
123
126
} ) ;
124
127
}
125
128
@@ -156,7 +159,10 @@ export function BlueprintPlaygroundUI(props: {
156
159
} ) {
157
160
const trackEvent = useTrack ( ) ;
158
161
const parameters = useMemo ( ( ) => {
159
- return modifyParametersForPlayground ( props . metadata . parameters ) ;
162
+ const filteredParams = props . metadata . parameters ?. filter (
163
+ isOpenAPIV3ParameterObject ,
164
+ ) ;
165
+ return modifyParametersForPlayground ( filteredParams || [ ] ) ;
160
166
} , [ props . metadata . parameters ] ) ;
161
167
162
168
const formSchema = useMemo ( ( ) => {
@@ -166,7 +172,11 @@ export function BlueprintPlaygroundUI(props: {
166
172
const defaultValues = useMemo ( ( ) => {
167
173
const values : Record < string , string | number > = { } ;
168
174
for ( const param of parameters ) {
169
- values [ param . name ] = param . default || "" ;
175
+ if ( param . schema && "type" in param . schema && param . schema . default ) {
176
+ values [ param . name ] = param . schema . default ;
177
+ } else {
178
+ values [ param . name ] = "" ;
179
+ }
170
180
}
171
181
return values ;
172
182
} , [ parameters ] ) ;
@@ -200,7 +210,7 @@ export function BlueprintPlaygroundUI(props: {
200
210
< form onSubmit = { form . handleSubmit ( onSubmit ) } >
201
211
< div className = "flex grow flex-col" >
202
212
< BlueprintMetaHeader
203
- title = { props . metadata . summary }
213
+ title = { props . metadata . summary || "Blueprint Playground" }
204
214
description = { props . metadata . description }
205
215
backLink = { props . backLink }
206
216
/>
@@ -263,7 +273,7 @@ export function BlueprintPlaygroundUI(props: {
263
273
264
274
function BlueprintMetaHeader ( props : {
265
275
title : string ;
266
- description : string ;
276
+ description : string | undefined ;
267
277
backLink : string ;
268
278
} ) {
269
279
return (
@@ -285,9 +295,11 @@ function BlueprintMetaHeader(props: {
285
295
< h1 className = "font-semibold text-2xl tracking-tight lg:text-3xl" >
286
296
{ props . title }
287
297
</ h1 >
288
- < p className = "mt-1 text-muted-foreground text-sm" >
289
- { props . description }
290
- </ p >
298
+ { props . description && (
299
+ < p className = "mt-1 text-muted-foreground text-sm" >
300
+ { props . description }
301
+ </ p >
302
+ ) }
291
303
</ div >
292
304
</ div >
293
305
</ div >
@@ -457,6 +469,11 @@ function ParameterSection(props: {
457
469
< h3 className = "mb-3 font-medium text-sm" > { props . title } </ h3 >
458
470
< div className = "overflow-hidden rounded-lg border" >
459
471
{ props . parameters . map ( ( param , i ) => {
472
+ const description =
473
+ param . schema && "type" in param . schema
474
+ ? param . schema . description
475
+ : undefined ;
476
+
460
477
const hasError = ! ! props . form . formState . errors [ param . name ] ;
461
478
return (
462
479
< FormField
@@ -517,7 +534,7 @@ function ParameterSection(props: {
517
534
{ ...field }
518
535
className = { cn (
519
536
"h-auto truncate rounded-none border-0 bg-transparent py-3 font-mono text-sm focus-visible:ring-0 focus-visible:ring-offset-0" ,
520
- param . description && "lg:pr-10" ,
537
+ description && "lg:pr-10" ,
521
538
hasError && "text-destructive-text" ,
522
539
) }
523
540
placeholder = {
@@ -528,8 +545,8 @@ function ParameterSection(props: {
528
545
: "Value"
529
546
}
530
547
/>
531
- { param . description && (
532
- < ToolTipLabel label = { param . description } >
548
+ { description && (
549
+ < ToolTipLabel label = { description } >
533
550
< Button
534
551
asChild
535
552
variant = "ghost"
@@ -651,32 +668,63 @@ function ResponseSection(props: {
651
668
) ;
652
669
}
653
670
654
- function createParametersFormSchema ( parameters : BlueprintParameter [ ] ) {
655
- const shape : z . ZodRawShape = { } ;
656
- for ( const param of parameters ) {
657
- // integer
658
- if ( param . type === "integer" ) {
671
+ function openAPIV3ParamToZodFormSchema ( param : BlueprintParameter ) {
672
+ if ( ! param . schema ) {
673
+ return ;
674
+ }
675
+
676
+ if ( ! ( "type" in param . schema ) ) {
677
+ return ;
678
+ }
679
+
680
+ switch ( param . schema . type ) {
681
+ case "integer" : {
659
682
const intSchema = z . coerce
660
683
. number ( {
661
684
message : "Must be an integer" ,
662
685
} )
663
686
. int ( {
664
687
message : "Must be an integer" ,
665
688
} ) ;
666
- shape [ param . name ] = param . required
689
+ return param . required
667
690
? intSchema . min ( 1 , {
668
691
message : "Required" ,
669
692
} )
670
693
: intSchema . optional ( ) ;
671
694
}
672
695
673
- // default: string
674
- else {
675
- shape [ param . name ] = param . required
676
- ? z . string ( ) . min ( 1 , {
696
+ case "number" : {
697
+ const numberSchema = z . coerce . number ( ) ;
698
+ return param . required
699
+ ? numberSchema . min ( 1 , {
677
700
message : "Required" ,
678
701
} )
679
- : z . string ( ) . optional ( ) ;
702
+ : numberSchema . optional ( ) ;
703
+ }
704
+
705
+ case "boolean" : {
706
+ const booleanSchema = z . coerce . boolean ( ) ;
707
+ return param . required ? booleanSchema : booleanSchema . optional ( ) ;
708
+ }
709
+
710
+ // everything else - just accept it as a string;
711
+ default : {
712
+ const stringSchema = z . string ( ) ;
713
+ return param . required
714
+ ? stringSchema . min ( 1 , {
715
+ message : "Required" ,
716
+ } )
717
+ : stringSchema . optional ( ) ;
718
+ }
719
+ }
720
+ }
721
+
722
+ function createParametersFormSchema ( parameters : BlueprintParameter [ ] ) {
723
+ const shape : z . ZodRawShape = { } ;
724
+ for ( const param of parameters ) {
725
+ const paramSchema = openAPIV3ParamToZodFormSchema ( param ) ;
726
+ if ( paramSchema ) {
727
+ shape [ param . name ] = paramSchema ;
680
728
}
681
729
}
682
730
@@ -747,3 +795,9 @@ function ElapsedTimeCounter() {
747
795
</ span >
748
796
) ;
749
797
}
798
+
799
+ function isOpenAPIV3ParameterObject (
800
+ x : OpenAPIV3 . ParameterObject | OpenAPIV3 . ReferenceObject ,
801
+ ) : x is OpenAPIV3 . ParameterObject {
802
+ return ! ( "$ref" in x ) ;
803
+ }
0 commit comments