From 0cd8b56adf3ba36a11e4cdf63ccde8c965113cd8 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 13 May 2024 15:42:36 +0300 Subject: [PATCH] docs: improve API testing feature --- .../ApiRunner/ParamInputs/Array/index.tsx | 98 ++++++++++++++++ .../ApiRunner/ParamInputs/Default/index.tsx | 102 +++++++++++++++++ .../ApiRunner/ParamInputs/Object/index.tsx | 45 ++++++++ .../ApiRunner/ParamInputs/index.tsx | 35 ++++++ .../{CodeBlock => }/ApiRunner/index.tsx | 106 +++++++----------- .../src/components/CodeBlock/index.tsx | 8 +- www/packages/docs-ui/src/components/index.ts | 1 + www/packages/docs-ui/src/utils/index.ts | 1 + .../docs-ui/src/utils/set-obj-value.ts | 38 +++++++ www/packages/docs-ui/tsconfig.json | 2 +- 10 files changed, 368 insertions(+), 68 deletions(-) create mode 100644 www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Array/index.tsx create mode 100644 www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Default/index.tsx create mode 100644 www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Object/index.tsx create mode 100644 www/packages/docs-ui/src/components/ApiRunner/ParamInputs/index.tsx rename www/packages/docs-ui/src/components/{CodeBlock => }/ApiRunner/index.tsx (57%) create mode 100644 www/packages/docs-ui/src/utils/set-obj-value.ts diff --git a/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Array/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Array/index.tsx new file mode 100644 index 0000000000000..bb7ad110dfcd4 --- /dev/null +++ b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Array/index.tsx @@ -0,0 +1,98 @@ +"use client" + +import React, { useEffect, useState } from "react" +import { ApiRunnerParamInput, ApiRunnerParamInputProps } from "../Default" +import clsx from "clsx" +import setObjValue from "@/utils/set-obj-value" +import { Button } from "../../../.." +import { Minus, Plus } from "@medusajs/icons" + +export const ApiRunnerParamArrayInput = ({ + paramName, + paramValue, + objPath, + setValue, +}: ApiRunnerParamInputProps) => { + const [itemsValue, setItemsValue] = useState(paramValue) + + useEffect(() => { + setValue((prev: unknown) => { + return typeof prev === "object" + ? setObjValue({ + obj: { ...prev }, + value: itemsValue, + path: `${objPath.length ? `${objPath}.` : ""}${paramName}`, + }) + : itemsValue + }) + }, [itemsValue]) + + if (!Array.isArray(paramValue)) { + return ( + + ) + } + + return ( +
+ + {paramName} Array Items + + {(itemsValue as unknown[]).map((value, index) => ( +
0 && + "flex gap-docs_0.5 items-center justify-center mt-docs_0.5" + )} + > + + {index > 0 && ( + + )} +
+ ))} + +
+ ) +} diff --git a/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Default/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Default/index.tsx new file mode 100644 index 0000000000000..e4dc92a4de98c --- /dev/null +++ b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Default/index.tsx @@ -0,0 +1,102 @@ +import React from "react" +import { InputText } from "../../../.." +import setObjValue from "../../../../utils/set-obj-value" +import { ApiRunnerParamObjectInput } from "../Object" +import { ApiRunnerParamArrayInput } from "../Array" + +export type ApiRunnerParamInputProps = { + paramName: string + paramValue: unknown + objPath: string + setValue: React.Dispatch> +} + +export const ApiRunnerParamInput = ({ + paramName, + paramValue, + objPath, + setValue, +}: ApiRunnerParamInputProps) => { + if (Array.isArray(paramValue)) { + return ( + + ) + } + if (typeof paramValue === "object") { + return ( + + ) + } + + return ( + { + setValue((prev: unknown) => { + if (Array.isArray(prev)) { + // try to get index from param name + const splitPath = objPath.split(".") + // if param is in an object in the array, the index is + // the last item of the `objPath`. Otherwise, it's in the param name + const index = ( + objPath.length > 0 ? splitPath[splitPath.length - 1] : paramName + ) + .replace("[", "") + .replace("]", "") + const intIndex = parseInt(index) + + // if we can't get the index from the param name or obj path + // just insert the value to the end of the array. + if (Number.isNaN(intIndex)) { + return [...prev, e.target.value] + } + + // if the param is within an object, the value to be set + // is the updated value of the object. Otherwise, it's just the + // value of the item. + const transformedValue = + prev.length > 0 && typeof prev[0] === "object" + ? setObjValue({ + obj: { ...prev[intIndex] }, + value: e.target.value, + path: paramName, + }) + : e.target.value + + return [ + ...prev.slice(0, intIndex), + transformedValue, + ...prev.slice(intIndex + 1), + ] + } + + return typeof prev === "object" + ? setObjValue({ + obj: { ...prev }, + value: e.target.value, + path: `${objPath.length ? `${objPath}.` : ""}${paramName}`, + }) + : e.target.value + }) + }} + placeholder={paramName} + value={ + typeof paramValue === "string" + ? (paramValue as string) + : typeof paramValue === "number" + ? (paramValue as number) + : `${paramValue}` + } + /> + ) +} diff --git a/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Object/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Object/index.tsx new file mode 100644 index 0000000000000..243cbfddeb1f3 --- /dev/null +++ b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/Object/index.tsx @@ -0,0 +1,45 @@ +import React from "react" +import { ApiRunnerParamInput, ApiRunnerParamInputProps } from "../Default" +import clsx from "clsx" + +export const ApiRunnerParamObjectInput = ({ + paramName, + paramValue, + objPath, + ...props +}: ApiRunnerParamInputProps) => { + if (typeof paramValue !== "object") { + return ( + + ) + } + + return ( +
+ + {paramName} Properties + + {Object.entries(paramValue as Record).map( + ([key, value], index) => ( + + ) + )} +
+ ) +} diff --git a/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/index.tsx new file mode 100644 index 0000000000000..091cf774c1553 --- /dev/null +++ b/www/packages/docs-ui/src/components/ApiRunner/ParamInputs/index.tsx @@ -0,0 +1,35 @@ +import React from "react" +import { ApiRunnerParamInput } from "./Default" + +export type ApiRunnerParamInputsProps = { + data: Record + title: string + baseObjPath: string + setValue: React.Dispatch> +} + +export const ApiRunnerParamInputs = ({ + data, + title, + baseObjPath, + setValue, +}: ApiRunnerParamInputsProps) => { + return ( +
+ + {title} + +
+ {Object.keys(data).map((pathParam, index) => ( + + ))} +
+
+ ) +} diff --git a/www/packages/docs-ui/src/components/CodeBlock/ApiRunner/index.tsx b/www/packages/docs-ui/src/components/ApiRunner/index.tsx similarity index 57% rename from www/packages/docs-ui/src/components/CodeBlock/ApiRunner/index.tsx rename to www/packages/docs-ui/src/components/ApiRunner/index.tsx index 7101b95198ebf..5d7465be9d9be 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/ApiRunner/index.tsx +++ b/www/packages/docs-ui/src/components/ApiRunner/index.tsx @@ -2,11 +2,12 @@ import React from "react" import { useEffect, useMemo, useState } from "react" -import { useRequestRunner } from "../../../hooks" -import { CodeBlock } from ".." -import { Card } from "../../Card" -import { Button, InputText } from "../../.." -import { ApiMethod, ApiDataOptions, ApiTestingOptions } from "types" +import { useRequestRunner } from "../../hooks" +import { CodeBlock } from "../CodeBlock" +import { Card } from "../Card" +import { Button } from "../.." +import { ApiMethod, ApiTestingOptions } from "types" +import { ApiRunnerParamInputs } from "./ParamInputs" type ApiRunnerProps = { apiMethod: ApiMethod @@ -72,69 +73,46 @@ export const ApiRunner = ({ } }, [isRunning, ran]) - const getParamsElms = ({ - data, - title, - nameInApiOptions, - }: { - data: ApiDataOptions - title: string - nameInApiOptions: "pathData" | "bodyData" | "queryData" - }) => ( -
- - {title} - -
- {Object.keys(data).map((pathParam, index) => ( - - setApiTestingOptions((prev) => ({ - ...prev, - [nameInApiOptions]: { - ...prev[nameInApiOptions], - [pathParam]: e.target.value, - }, - })) - } - key={index} - placeholder={pathParam} - value={ - typeof data[pathParam] === "string" - ? (data[pathParam] as string) - : typeof data[pathParam] === "number" - ? (data[pathParam] as number) - : `${data[pathParam]}` - } - /> - ))} -
-
- ) - return ( <> {manualTestTrigger && ( - {apiTestingOptions.pathData && - getParamsElms({ - data: apiTestingOptions.pathData, - title: "Path Parameters", - nameInApiOptions: "pathData", - })} - {apiTestingOptions.bodyData && - getParamsElms({ - data: apiTestingOptions.bodyData, - title: "Request Body Parameters", - nameInApiOptions: "bodyData", - })} - {apiTestingOptions.queryData && - getParamsElms({ - data: apiTestingOptions.queryData, - title: "Request Query Parameters", - nameInApiOptions: "queryData", - })} + {apiTestingOptions.pathData && ( + + > + } + /> + )} + {apiTestingOptions.bodyData && ( + + > + } + /> + )} + {apiTestingOptions.queryData && ( + + > + } + /> + )}