Skip to content

Commit 216f069

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 introduces the `openapi-types` package and updates the handling of OpenAPI specifications in the dashboard application. It enhances type safety and flexibility in managing API parameters and responses. ### Detailed summary - Added `openapi-types` dependency. - Updated `blueprintSpec` to use `OpenAPIV3.Document`. - Modified parameter handling in `BlueprintPlaygroundUI` to filter and process OpenAPI parameters. - Enhanced type definitions for `BlueprintParameter` using `OpenAPIV3.ParameterObject`. - Updated rendering logic in `BlueprintCard` to handle optional descriptions and titles. - Refactored utility functions to align with new OpenAPI types. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent fa26eef commit 216f069

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)