Skip to content

Commit d7d9415

Browse files
committed
[TOOL-2801] Insight Playground: Use OpenAPIV3 types (#5804)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the handling of OpenAPI specifications within the codebase, improving type definitions, and refining the UI components to accommodate optional fields and better manage parameters. ### Detailed summary - Added `openapi-types` dependency in `package.json`. - Updated `blueprintSpec` to use optional chaining for safer access. - Modified `BlueprintCard` to handle optional `description` and `title`. - Changed `BlueprintParameter` type to use `OpenAPIV3.ParameterObject`. - Enhanced `BlueprintPlaygroundUI` to filter and manage parameters more effectively. - Updated parameter handling in forms to leverage new schema definitions. - Refined UI components to conditionally render descriptions and titles. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent b2a52d9 commit d7d9415

File tree

7 files changed

+613
-301
lines changed

7 files changed

+613
-301
lines changed

apps/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"next-seo": "^6.5.0",
7474
"next-themes": "^0.4.4",
7575
"nextjs-toploader": "^1.6.12",
76+
"openapi-types": "^12.1.3",
7677
"papaparse": "^5.4.1",
7778
"pluralize": "^8.0.0",
7879
"posthog-js": "1.67.1",

apps/dashboard/src/app/team/[team_slug]/[project_slug]/insight/[blueprint_slug]/blueprint-playground.client.tsx

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
PlayIcon,
2626
} from "lucide-react";
2727
import Link from "next/link";
28+
import type { OpenAPIV3 } from "openapi-types";
2829
import { useEffect, useMemo, useState } from "react";
2930
import { type UseFormReturn, useForm } from "react-hook-form";
3031
import { z } from "zod";
@@ -118,8 +119,10 @@ function modifyParametersForPlayground(_parameters: BlueprintParameter[]) {
118119
name: "chainId",
119120
in: "path",
120121
required: true,
121-
description: "Chain ID",
122-
type: "integer",
122+
schema: {
123+
type: "integer",
124+
description: "Chain ID of the blockchain",
125+
},
123126
});
124127
}
125128

@@ -156,7 +159,10 @@ export function BlueprintPlaygroundUI(props: {
156159
}) {
157160
const trackEvent = useTrack();
158161
const parameters = useMemo(() => {
159-
return modifyParametersForPlayground(props.metadata.parameters);
162+
const filteredParams = props.metadata.parameters?.filter(
163+
isOpenAPIV3ParameterObject,
164+
);
165+
return modifyParametersForPlayground(filteredParams || []);
160166
}, [props.metadata.parameters]);
161167

162168
const formSchema = useMemo(() => {
@@ -166,7 +172,11 @@ export function BlueprintPlaygroundUI(props: {
166172
const defaultValues = useMemo(() => {
167173
const values: Record<string, string | number> = {};
168174
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+
}
170180
}
171181
return values;
172182
}, [parameters]);
@@ -200,7 +210,7 @@ export function BlueprintPlaygroundUI(props: {
200210
<form onSubmit={form.handleSubmit(onSubmit)}>
201211
<div className="flex grow flex-col">
202212
<BlueprintMetaHeader
203-
title={props.metadata.summary}
213+
title={props.metadata.summary || "Blueprint Playground"}
204214
description={props.metadata.description}
205215
backLink={props.backLink}
206216
/>
@@ -263,7 +273,7 @@ export function BlueprintPlaygroundUI(props: {
263273

264274
function BlueprintMetaHeader(props: {
265275
title: string;
266-
description: string;
276+
description: string | undefined;
267277
backLink: string;
268278
}) {
269279
return (
@@ -285,9 +295,11 @@ function BlueprintMetaHeader(props: {
285295
<h1 className="font-semibold text-2xl tracking-tight lg:text-3xl">
286296
{props.title}
287297
</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+
)}
291303
</div>
292304
</div>
293305
</div>
@@ -457,6 +469,11 @@ function ParameterSection(props: {
457469
<h3 className="mb-3 font-medium text-sm"> {props.title} </h3>
458470
<div className="overflow-hidden rounded-lg border">
459471
{props.parameters.map((param, i) => {
472+
const description =
473+
param.schema && "type" in param.schema
474+
? param.schema.description
475+
: undefined;
476+
460477
const hasError = !!props.form.formState.errors[param.name];
461478
return (
462479
<FormField
@@ -517,7 +534,7 @@ function ParameterSection(props: {
517534
{...field}
518535
className={cn(
519536
"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",
521538
hasError && "text-destructive-text",
522539
)}
523540
placeholder={
@@ -528,8 +545,8 @@ function ParameterSection(props: {
528545
: "Value"
529546
}
530547
/>
531-
{param.description && (
532-
<ToolTipLabel label={param.description}>
548+
{description && (
549+
<ToolTipLabel label={description}>
533550
<Button
534551
asChild
535552
variant="ghost"
@@ -651,32 +668,63 @@ function ResponseSection(props: {
651668
);
652669
}
653670

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": {
659682
const intSchema = z.coerce
660683
.number({
661684
message: "Must be an integer",
662685
})
663686
.int({
664687
message: "Must be an integer",
665688
});
666-
shape[param.name] = param.required
689+
return param.required
667690
? intSchema.min(1, {
668691
message: "Required",
669692
})
670693
: intSchema.optional();
671694
}
672695

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, {
677700
message: "Required",
678701
})
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;
680728
}
681729
}
682730

@@ -747,3 +795,9 @@ function ElapsedTimeCounter() {
747795
</span>
748796
);
749797
}
798+
799+
function isOpenAPIV3ParameterObject(
800+
x: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject,
801+
): x is OpenAPIV3.ParameterObject {
802+
return !("$ref" in x);
803+
}

0 commit comments

Comments
 (0)