Fuma studio

Scheme

Installation

npx shadcn@latest add http://fumastudio/com/r/scheme.json
components/fumastudio/scheme.tsx
"use client";

import { useMockRequest } from "@/components/fumastudio/mock-request";
import { Schema } from "@/components/fumastudio/schema";
import {
	Select,
	SelectContent,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from "@/components/ui/select";
import { HttpCode } from "@/lib/http-codes";
import {
	AllSchema,
	ApiKeyHeaderScheme,
	ApiKeyQueryScheme,
	BasicAuthScheme,
	BearerAuthScheme,
	ObjectSchema,
	ReplySchema,
} from "@trythis/js-schema";
import { useEffect, useState } from "react";

export type AuthSchemes =
	| BasicAuthScheme
	| BearerAuthScheme
	| ApiKeyHeaderScheme
	| ApiKeyQueryScheme;

const AuthorizationScheme = (props: { schema: AuthSchemes[] }) => {
	const [selectedAuth, setSelectedAuth] = useState(
		props.schema?.[0]?.type || "",
	);
	const [selectedScheme, setSelectedScheme] = useState<AuthSchemes | null>(
		null,
	);

	useEffect(() => {
		if (props.schema && props.schema.length > 0) {
			const item =
				props.schema.find(
					(item) => item.type === selectedAuth,
				) || null;
			setSelectedScheme(item);
		}
	}, [selectedAuth, props.schema]);

	if (!props.schema) return;

	return (
		<>
			<div className="flex flex-col w-full gap-y-4">
				<div className="flex items-baseline border-b pb-2.5 border-gray-100 dark:border-gray-800 w-full">
					<h4 className="flex-1 mb-0 font-inter text-[1.125em] leading-normal font-semibold">
						Authorizations
					</h4>

					<div className="flex items-center font-mono text-xs gap-x-3">
						<div className="px-2 py-0.5 font-medium text-gray-600 dark:text-gray-300 hover:text-zinc-950 dark:hover:text-white transition-all">
							<Select
								value={selectedAuth}
								onValueChange={(v) =>
									setSelectedAuth(
										v as AuthSchemes["type"],
									)
								}>
								<SelectTrigger className="h-8 text-xs">
									<SelectValue />
								</SelectTrigger>
								<SelectContent className="[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2 ">
									{props.schema &&
										props.schema
											.length > 0 &&
										props.schema.map(
											({
												type,
											}: AuthSchemes) => (
												<SelectItem
													key={
														type
													}
													value={
														type
													}
													className="text-xs">
													{
														type
													}
												</SelectItem>
											),
										)}
								</SelectContent>
							</Select>
						</div>
					</div>
				</div>
			</div>

			{selectedScheme && (
				<Schema
					schema={selectedScheme}
					depth={0}
					path="authorization"
					type="authorization"
				/>
			)}
		</>
	);
};

const QueryParamsSchema = (props: { schema: ObjectSchema }) => {
	return (
		<>
			<div className="flex flex-col w-full gap-y-4">
				<div className="flex items-baseline border-b pb-2.5 border-gray-100 dark:border-gray-800 w-full">
					<h4 className="flex-1 mb-0 font-inter text-[1.125em] leading-normal font-semibold">
						Query Parameters
					</h4>
					<div className="flex items-center"></div>
				</div>
			</div>
			<Schema
				schema={props.schema}
				depth={0}
				path="query"
				type="query"
			/>
		</>
	);
};

const PathParamsSchema = (props: { schema: ObjectSchema }) => {
	return (
		<>
			<div className="flex flex-col w-full gap-y-4">
				<div className="flex items-baseline border-b pb-2.5 border-gray-100 dark:border-gray-800 w-full">
					<h4 className="flex-1 mb-0 font-inter text-[1.125em] leading-normal font-semibold">
						Path Parameters
					</h4>
					<div className="flex items-center"></div>
				</div>
			</div>
			<Schema
				schema={props.schema}
				depth={0}
				path="parameter"
				type="parameter"
			/>
		</>
	);
};

const RequestBodySchema = (props: { schema: ObjectSchema }) => {
	return (
		<>
			<div className="flex items-baseline border-b pb-2.5 border-gray-100 dark:border-gray-800 w-full">
				<h4 className="flex-1 mb-0 font-inter text-[1.125em] leading-normal font-semibold">
					Body
				</h4>
				<span className="px-2 py-0.5 font-mono text-xs font-medium text-gray-600 dark:text-gray-300 hover:text-gray-950 dark:hover:text-white">
					application/json
				</span>
			</div>

			<Schema
				schema={props.schema}
				depth={0}
				path="body"
				type="body"
			/>
		</>
	);
};

type Properties = NonNullable<ReplySchema["properties"]>;
type ResponseBodySchemaProps = {
	httpCodes: HttpCode[];
	schema: ReplySchema;
};

const ResponseBodySchema = (props: ResponseBodySchemaProps) => {
	const [code, setCode] = useState(String(props.httpCodes.at(0)?.status));
	const [schema, setSchema] = useState<AllSchema | null>(null);
	const { setResponseSlug } = useMockRequest();

	useEffect(() => {
		if (!props.httpCodes || !props.schema) return;

		const status = props.httpCodes.find(
			(http) => http.status === Number(code),
		);

		if (!status) {
			console.log("Status not found: ", status);
			return;
		}
		const schema = (props.schema?.properties as Properties)[
			status.slug
		];

		if (schema) {
			setResponseSlug(status.slug);
			setSchema(schema);
		}
	}, [code]);

	return (
		<>
			<div className="flex items-baseline border-b pb-2.5 border-gray-100 dark:border-gray-800 w-full">
				<h4 className="flex-1 mb-0 font-inter text-[1.125em] leading-normal font-semibold">
					Response
				</h4>
				<div className="flex items-center font-mono text-xs gap-x-3">
					<div className="px-2 py-0.5 font-medium text-gray-600 dark:text-gray-300 hover:text-zinc-950 dark:hover:text-white transition-all">
						<Select
							value={code}
							onValueChange={setCode}>
							<SelectTrigger className="h-8 text-xs">
								<SelectValue />
							</SelectTrigger>
							<SelectContent className="[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2 ">
								{props.httpCodes.map(
									({ slug, status }) => (
										<SelectItem
											key={slug}
											value={String(
												status,
											)}
											className="text-xs">
											{status}
										</SelectItem>
									),
								)}
							</SelectContent>
						</Select>
					</div>

					{schema && schema.contentType && (
						<span className="px-2 py-0.5 font-medium text-gray-600 dark:text-gray-300 hover:text-gray-950 dark:hover:text-white">
							{schema.contentType}
						</span>
					)}
				</div>
			</div>

			<Schema
				schema={schema!}
				depth={0}
				path="response"
				type="response"
			/>
		</>
	);
};

export {
	AuthorizationScheme,
	PathParamsSchema,
	QueryParamsSchema,
	RequestBodySchema,
	ResponseBodySchema,
};

Props

On this page