fumadocs-openapi 6.0.1 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-routes.d.ts +15 -0
- package/dist/build-routes.d.ts.map +1 -0
- package/dist/build-routes.js +38 -0
- package/dist/generate-file.d.ts +38 -0
- package/dist/generate-file.d.ts.map +1 -0
- package/dist/generate-file.js +118 -0
- package/dist/generate.d.ts +48 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +129 -0
- package/dist/index.d.ts +4 -274
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -389
- package/dist/render/codeblock.d.ts +9 -0
- package/dist/render/codeblock.d.ts.map +1 -0
- package/dist/render/codeblock.js +13 -0
- package/dist/render/heading.d.ts +4 -0
- package/dist/render/heading.d.ts.map +1 -0
- package/dist/render/heading.js +6 -0
- package/dist/render/markdown.d.ts +5 -0
- package/dist/render/markdown.d.ts.map +1 -0
- package/dist/render/markdown.js +25 -0
- package/dist/render/operation.d.ts +17 -0
- package/dist/render/operation.d.ts.map +1 -0
- package/dist/render/operation.js +230 -0
- package/dist/render/playground.d.ts +66 -0
- package/dist/render/playground.d.ts.map +1 -0
- package/dist/render/playground.js +181 -0
- package/dist/render/renderer.d.ts +76 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +23 -0
- package/dist/render/schema.d.ts +29 -0
- package/dist/render/schema.d.ts.map +1 -0
- package/dist/render/schema.js +151 -0
- package/dist/requests/curl.d.ts +3 -0
- package/dist/requests/curl.d.ts.map +1 -0
- package/dist/requests/curl.js +33 -0
- package/dist/requests/go.d.ts +3 -0
- package/dist/requests/go.d.ts.map +1 -0
- package/dist/requests/go.js +54 -0
- package/dist/requests/javascript.d.ts +3 -0
- package/dist/requests/javascript.d.ts.map +1 -0
- package/dist/requests/javascript.js +49 -0
- package/dist/requests/python.d.ts +3 -0
- package/dist/requests/python.d.ts.map +1 -0
- package/dist/requests/python.js +45 -0
- package/dist/scalar/client.d.ts +6 -0
- package/dist/scalar/client.d.ts.map +1 -0
- package/dist/scalar/client.js +25 -0
- package/dist/scalar/index.d.ts +4 -173
- package/dist/scalar/index.d.ts.map +1 -0
- package/dist/scalar/index.js +4 -11
- package/dist/server/api-page.d.ts +33 -0
- package/dist/server/api-page.d.ts.map +1 -0
- package/dist/server/api-page.js +59 -0
- package/dist/server/create-method.d.ts +7 -0
- package/dist/server/create-method.d.ts.map +1 -0
- package/dist/server/create-method.js +12 -0
- package/dist/server/create.d.ts +16 -0
- package/dist/server/create.d.ts.map +1 -0
- package/dist/server/create.js +11 -0
- package/dist/server/index.d.ts +3 -221
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -1493
- package/dist/server/proxy.d.ts +8 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +53 -0
- package/dist/server/source-api.d.ts +8 -0
- package/dist/server/source-api.d.ts.map +1 -0
- package/dist/server/source-api.js +34 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/ui/client.d.ts +22 -0
- package/dist/ui/client.d.ts.map +1 -0
- package/dist/ui/client.js +10 -0
- package/dist/ui/components/input.d.ts +6 -0
- package/dist/ui/components/input.d.ts.map +1 -0
- package/dist/ui/components/input.js +10 -0
- package/dist/ui/components/method-label.d.ts +5 -0
- package/dist/ui/components/method-label.d.ts.map +1 -0
- package/dist/ui/components/method-label.js +33 -0
- package/dist/ui/components/select.d.ts +14 -0
- package/dist/ui/components/select.d.ts.map +1 -0
- package/dist/ui/components/select.js +24 -0
- package/dist/ui/components/variants.d.ts +6 -0
- package/dist/ui/components/variants.d.ts.map +1 -0
- package/dist/ui/components/variants.js +26 -0
- package/dist/ui/contexts/api.d.ts +28 -0
- package/dist/ui/contexts/api.d.ts.map +1 -0
- package/dist/ui/contexts/api.js +74 -0
- package/dist/ui/contexts/schema.d.ts +17 -0
- package/dist/ui/contexts/schema.d.ts.map +1 -0
- package/dist/ui/contexts/schema.js +8 -0
- package/dist/ui/index.d.ts +12 -302
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +18 -98
- package/dist/ui/playground/fetcher.d.ts +34 -0
- package/dist/ui/playground/fetcher.d.ts.map +1 -0
- package/dist/ui/{fetcher-CsHhplmD.js → playground/fetcher.js} +45 -44
- package/dist/ui/playground/get-default-values.d.ts +4 -0
- package/dist/ui/playground/get-default-values.d.ts.map +1 -0
- package/dist/ui/playground/get-default-values.js +24 -0
- package/dist/ui/playground/index.d.ts +44 -0
- package/dist/ui/playground/index.d.ts.map +1 -0
- package/dist/ui/playground/index.js +187 -0
- package/dist/ui/playground/inputs.d.ts +23 -0
- package/dist/ui/playground/inputs.d.ts.map +1 -0
- package/dist/ui/playground/inputs.js +172 -0
- package/dist/ui/playground/resolve.d.ts +6 -0
- package/dist/ui/playground/resolve.d.ts.map +1 -0
- package/dist/ui/playground/resolve.js +14 -0
- package/dist/ui/playground/status-info.d.ts +8 -0
- package/dist/ui/playground/status-info.d.ts.map +1 -0
- package/dist/ui/playground/status-info.js +40 -0
- package/dist/ui/server-select.d.ts +3 -0
- package/dist/ui/server-select.d.ts.map +1 -0
- package/dist/ui/server-select.js +27 -0
- package/dist/utils/combine-schema.d.ts +6 -0
- package/dist/utils/combine-schema.d.ts.map +1 -0
- package/dist/utils/combine-schema.js +46 -0
- package/dist/utils/generate-document.d.ts +20 -0
- package/dist/utils/generate-document.d.ts.map +1 -0
- package/dist/utils/generate-document.js +82 -0
- package/dist/utils/generate-sample.d.ts +33 -0
- package/dist/utils/generate-sample.d.ts.map +1 -0
- package/dist/utils/generate-sample.js +97 -0
- package/dist/utils/get-security.d.ts +8 -0
- package/dist/utils/get-security.d.ts.map +1 -0
- package/dist/utils/get-security.js +23 -0
- package/dist/utils/get-typescript-schema.d.ts +4 -0
- package/dist/utils/get-typescript-schema.d.ts.map +1 -0
- package/dist/utils/get-typescript-schema.js +18 -0
- package/dist/utils/id-to-title.d.ts +2 -0
- package/dist/utils/id-to-title.d.ts.map +1 -0
- package/dist/utils/id-to-title.js +17 -0
- package/dist/utils/input-to-string.d.ts +5 -0
- package/dist/utils/input-to-string.d.ts.map +1 -0
- package/dist/utils/input-to-string.js +21 -0
- package/dist/utils/process-document.d.ts +14 -0
- package/dist/utils/process-document.d.ts.map +1 -0
- package/dist/utils/process-document.js +32 -0
- package/dist/utils/schema.d.ts +9 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +16 -0
- package/dist/utils/server-url.d.ts +2 -0
- package/dist/utils/server-url.d.ts.map +1 -0
- package/dist/utils/server-url.js +7 -0
- package/dist/utils/use-query.d.ts +6 -0
- package/dist/utils/use-query.d.ts.map +1 -0
- package/dist/utils/use-query.js +22 -0
- package/package.json +7 -7
- package/dist/scalar/client-client-BXAjVueF.js +0 -93
- package/dist/ui/client-client-CYO00OiB.js +0 -107
- package/dist/ui/index-client-BUeWwFWK.js +0 -1116
- package/dist/ui/server-select-client-Ct_HJ46K.js +0 -86
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { resolve } from '../../ui/playground/resolve';
|
|
2
|
+
export function getDefaultValue(item, references) {
|
|
3
|
+
if (item.type === 'object')
|
|
4
|
+
return Object.fromEntries(Object.entries(item.properties).map(([key, prop]) => [
|
|
5
|
+
key,
|
|
6
|
+
getDefaultValue(prop.type === 'ref' ? references[prop.schema] : prop, references),
|
|
7
|
+
]));
|
|
8
|
+
if (item.type === 'array')
|
|
9
|
+
return [];
|
|
10
|
+
if (item.type === 'null')
|
|
11
|
+
return null;
|
|
12
|
+
if (item.type === 'switcher') {
|
|
13
|
+
const first = Object.values(item.items).at(0);
|
|
14
|
+
if (!first)
|
|
15
|
+
return '';
|
|
16
|
+
return getDefaultValue(resolve(first, references), references);
|
|
17
|
+
}
|
|
18
|
+
if (item.type === 'file')
|
|
19
|
+
return undefined;
|
|
20
|
+
return String(item.defaultValue);
|
|
21
|
+
}
|
|
22
|
+
export function getDefaultValues(field, context) {
|
|
23
|
+
return Object.fromEntries(field.map((p) => [p.name, getDefaultValue(p, context)]));
|
|
24
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ReactElement, type HTMLAttributes, type FC, type ReactNode } from 'react';
|
|
2
|
+
import type { FieldPath, UseFormStateReturn, ControllerFieldState, ControllerRenderProps } from 'react-hook-form';
|
|
3
|
+
import type { FetchResult } from '../../ui/playground/fetcher';
|
|
4
|
+
import type { APIPlaygroundProps, PrimitiveRequestField, RequestSchema } from '../../render/playground';
|
|
5
|
+
interface FormValues {
|
|
6
|
+
authorization: string | {
|
|
7
|
+
username: string;
|
|
8
|
+
password: string;
|
|
9
|
+
};
|
|
10
|
+
path: Record<string, unknown>;
|
|
11
|
+
query: Record<string, unknown>;
|
|
12
|
+
header: Record<string, unknown>;
|
|
13
|
+
body: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface CustomField<TName extends FieldPath<FormValues>, Info> {
|
|
16
|
+
render: (props: {
|
|
17
|
+
/**
|
|
18
|
+
* Field Info
|
|
19
|
+
*/
|
|
20
|
+
info: Info;
|
|
21
|
+
field: ControllerRenderProps<FormValues, TName>;
|
|
22
|
+
fieldState: ControllerFieldState;
|
|
23
|
+
formState: UseFormStateReturn<FormValues>;
|
|
24
|
+
}) => ReactElement;
|
|
25
|
+
}
|
|
26
|
+
export declare function APIPlayground({ route, method, authorization, path, header, query, body, fields, schemas, proxyUrl, components: { ResultDisplay }, ...props }: APIPlaygroundProps & {
|
|
27
|
+
fields?: {
|
|
28
|
+
auth?: CustomField<'authorization', RequestSchema>;
|
|
29
|
+
path?: CustomField<`path.${string}`, PrimitiveRequestField>;
|
|
30
|
+
query?: CustomField<`query.${string}`, PrimitiveRequestField>;
|
|
31
|
+
header?: CustomField<`header.${string}`, PrimitiveRequestField>;
|
|
32
|
+
body?: CustomField<'body', RequestSchema>;
|
|
33
|
+
};
|
|
34
|
+
components?: Partial<{
|
|
35
|
+
ResultDisplay: FC<{
|
|
36
|
+
data: FetchResult;
|
|
37
|
+
}>;
|
|
38
|
+
}>;
|
|
39
|
+
} & HTMLAttributes<HTMLFormElement>): import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
export declare function CollapsiblePanel({ title, children, ...props }: HTMLAttributes<HTMLDivElement> & {
|
|
41
|
+
title: ReactNode;
|
|
42
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/playground/index.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EAInB,KAAK,EAAE,EAEP,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAM3D,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAe7B,UAAU,UAAU;IAClB,aAAa,EACT,MAAM,GACN;QACE,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACN,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI;IACpE,MAAM,EAAE,CAAC,KAAK,EAAE;QACd;;WAEG;QACH,IAAI,EAAE,IAAI,CAAC;QACX,KAAK,EAAE,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAChD,UAAU,EAAE,oBAAoB,CAAC;QACjC,SAAS,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;KAC3C,KAAK,YAAY,CAAC;CACpB;AAcD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,MAAc,EACd,aAAa,EACb,IAAS,EACT,MAAW,EACX,KAAU,EACV,IAAI,EACJ,MAAW,EACX,OAAO,EACP,QAAQ,EACR,UAAU,EAAE,EAAE,aAAoC,EAAO,EACzD,GAAG,KAAK,EACT,EAAE,kBAAkB,GAAG;IACtB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,WAAW,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,WAAW,CAAC,QAAQ,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC5D,KAAK,CAAC,EAAE,WAAW,CAAC,SAAS,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC9D,MAAM,CAAC,EAAE,WAAW,CAAC,UAAU,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAChE,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;KAC3C,CAAC;IAEF,UAAU,CAAC,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,EAAE,CAAC;YAAE,IAAI,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ,GAAG,cAAc,CAAC,eAAe,CAAC,2CAyOlC;AAiHD,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG;IAClC,KAAK,EAAE,SAAS,CAAC;CAClB,2CAeA"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo, useRef, useEffect, Fragment, } from 'react';
|
|
4
|
+
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|
5
|
+
import { cn, buttonVariants } from 'fumadocs-ui/components/api';
|
|
6
|
+
import { useApiContext } from '../../ui/contexts/api';
|
|
7
|
+
import { getDefaultValue, getDefaultValues, } from '../../ui/playground/get-default-values';
|
|
8
|
+
import { FieldSet, ObjectInput } from '../../ui/playground/inputs';
|
|
9
|
+
import { SchemaContext } from '../contexts/schema';
|
|
10
|
+
import { getStatusInfo } from '../../ui/playground/status-info';
|
|
11
|
+
import { getUrl } from '../../utils/server-url';
|
|
12
|
+
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
|
|
13
|
+
import { MethodLabel } from '../../ui/components/method-label';
|
|
14
|
+
import { useQuery } from '../../utils/use-query';
|
|
15
|
+
import ServerSelect from '../../ui/server-select';
|
|
16
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from 'fumadocs-ui/components/ui/collapsible';
|
|
17
|
+
import { ChevronDown } from 'lucide-react';
|
|
18
|
+
function defaultAuthValue(auth) {
|
|
19
|
+
if (!auth || auth.type === 'apiKey')
|
|
20
|
+
return '';
|
|
21
|
+
if (auth.type === 'http' && auth.scheme === 'basic') {
|
|
22
|
+
return {
|
|
23
|
+
username: '',
|
|
24
|
+
password: '',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return 'Bearer';
|
|
28
|
+
}
|
|
29
|
+
export function APIPlayground({ route, method = 'GET', authorization, path = [], header = [], query = [], body, fields = {}, schemas, proxyUrl, components: { ResultDisplay = DefaultResultDisplay } = {}, ...props }) {
|
|
30
|
+
const { serverRef } = useApiContext();
|
|
31
|
+
const dynamicRef = useRef(new Map());
|
|
32
|
+
const form = useForm({
|
|
33
|
+
defaultValues: {
|
|
34
|
+
authorization: defaultAuthValue(authorization),
|
|
35
|
+
path: getDefaultValues(path, schemas),
|
|
36
|
+
query: getDefaultValues(query, schemas),
|
|
37
|
+
header: getDefaultValues(header, schemas),
|
|
38
|
+
body: body ? getDefaultValue(body, schemas) : undefined,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const testQuery = useQuery(async (input) => {
|
|
42
|
+
const fetcher = await import('./fetcher').then((mod) => mod.createBrowserFetcher(body, schemas));
|
|
43
|
+
const query = { ...input.query };
|
|
44
|
+
const header = { ...input.header };
|
|
45
|
+
if (input.authorization && authorization) {
|
|
46
|
+
if (authorization.type === 'apiKey') {
|
|
47
|
+
if (authorization.in === 'header') {
|
|
48
|
+
header[authorization.name] = input.authorization;
|
|
49
|
+
}
|
|
50
|
+
else if (authorization.in === 'query') {
|
|
51
|
+
query[authorization.name] = input.authorization;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if ('cookie' in header) {
|
|
55
|
+
header.Cookie = header.cookie;
|
|
56
|
+
delete header.cookie;
|
|
57
|
+
}
|
|
58
|
+
header.Cookie = [
|
|
59
|
+
header.Cookie,
|
|
60
|
+
`${authorization.name}=${input.authorization}`,
|
|
61
|
+
]
|
|
62
|
+
.filter((s) => s.length > 0)
|
|
63
|
+
.join('; ');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (authorization.type === 'http' &&
|
|
67
|
+
authorization.scheme === 'basic') {
|
|
68
|
+
if (typeof input.authorization === 'object')
|
|
69
|
+
header.Authorization = `Basic ${btoa(`${input.authorization.username}:${input.authorization.password}`)}`;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
header.Authorization = input.authorization;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const serverUrl = serverRef.current
|
|
76
|
+
? getUrl(serverRef.current.url, serverRef.current.variables)
|
|
77
|
+
: window.location.origin;
|
|
78
|
+
let url = `${serverUrl}${createPathnameFromInput(route, input.path, query)}`;
|
|
79
|
+
if (proxyUrl) {
|
|
80
|
+
const updated = new URL(proxyUrl, window.location.origin);
|
|
81
|
+
updated.searchParams.append('url', url);
|
|
82
|
+
url = updated.toString();
|
|
83
|
+
}
|
|
84
|
+
return fetcher.fetch({
|
|
85
|
+
url: url.toString(),
|
|
86
|
+
header,
|
|
87
|
+
body: body
|
|
88
|
+
? {
|
|
89
|
+
mediaType: body.mediaType,
|
|
90
|
+
value: input.body,
|
|
91
|
+
}
|
|
92
|
+
: undefined,
|
|
93
|
+
dynamicFields: dynamicRef.current,
|
|
94
|
+
method,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!authorization)
|
|
99
|
+
return;
|
|
100
|
+
const key = `__fumadocs_auth_${JSON.stringify(authorization)}`;
|
|
101
|
+
const cached = localStorage.getItem(key);
|
|
102
|
+
if (cached)
|
|
103
|
+
form.setValue('authorization', JSON.parse(cached));
|
|
104
|
+
const subscription = form.watch((value, { name }) => {
|
|
105
|
+
if (!name || !name.startsWith('authorization') || !value.authorization)
|
|
106
|
+
return;
|
|
107
|
+
localStorage.setItem(key, JSON.stringify(value.authorization));
|
|
108
|
+
});
|
|
109
|
+
return () => {
|
|
110
|
+
subscription.unsubscribe();
|
|
111
|
+
};
|
|
112
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- mounted only once
|
|
113
|
+
}, []);
|
|
114
|
+
const onSubmit = form.handleSubmit((value) => {
|
|
115
|
+
testQuery.start(value);
|
|
116
|
+
});
|
|
117
|
+
function renderCustomField(fieldName, info, field, key) {
|
|
118
|
+
if (field) {
|
|
119
|
+
return (_jsx(Controller, { control: form.control, render: (props) => field.render({ ...props, info }), name: fieldName }, key));
|
|
120
|
+
}
|
|
121
|
+
return (_jsx(FieldSet, { name: info.name, fieldName: fieldName, field: info }, key));
|
|
122
|
+
}
|
|
123
|
+
return (_jsx(FormProvider, { ...form, children: _jsx(SchemaContext.Provider, { value: useMemo(() => ({ references: schemas, dynamic: dynamicRef }), [schemas]), children: _jsxs("form", { ...props, className: cn('not-prose flex flex-col gap-2 rounded-xl border p-3 shadow-md', props.className), onSubmit: onSubmit, children: [_jsx(FormHeader, { method: method, route: route, isLoading: testQuery.isLoading }), _jsx(CollapsiblePanel, { title: "Server URL", children: _jsx(ServerSelect, {}) }), header.length > 0 || authorization ? (_jsxs(CollapsiblePanel, { title: "Headers", children: [authorization?.type === 'http' &&
|
|
124
|
+
authorization.scheme === 'basic'
|
|
125
|
+
? renderCustomField('authorization', {
|
|
126
|
+
name: 'Authorization',
|
|
127
|
+
type: 'object',
|
|
128
|
+
isRequired: true,
|
|
129
|
+
properties: {
|
|
130
|
+
username: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
isRequired: true,
|
|
133
|
+
defaultValue: '',
|
|
134
|
+
},
|
|
135
|
+
password: {
|
|
136
|
+
type: 'string',
|
|
137
|
+
isRequired: true,
|
|
138
|
+
defaultValue: '',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
}, fields.auth)
|
|
142
|
+
: authorization
|
|
143
|
+
? renderCustomField('authorization', {
|
|
144
|
+
name: 'Authorization',
|
|
145
|
+
type: 'string',
|
|
146
|
+
isRequired: true,
|
|
147
|
+
description: 'The Authorization access token',
|
|
148
|
+
defaultValue: '',
|
|
149
|
+
}, fields.auth)
|
|
150
|
+
: null, header.map((field) => renderCustomField(`header.${field.name}`, field, fields.header, field.name))] })) : null, path.length > 0 ? (_jsx(CollapsiblePanel, { title: "Path", children: path.map((field) => renderCustomField(`path.${field.name}`, field, fields.path, field.name)) })) : null, query.length > 0 ? (_jsx(CollapsiblePanel, { title: "Query", children: query.map((field) => renderCustomField(`query.${field.name}`, field, fields.query, field.name)) })) : null, body ? (_jsx(CollapsiblePanel, { title: "Body", children: body.type === 'object' && !fields.body ? (_jsx(ObjectInput, { field: body, fieldName: "body" })) : (renderCustomField('body', body, fields.body)) })) : null, testQuery.data ? _jsx(ResultDisplay, { data: testQuery.data }) : null] }) }) }));
|
|
151
|
+
}
|
|
152
|
+
function createPathnameFromInput(route, path, query) {
|
|
153
|
+
let pathname = route;
|
|
154
|
+
for (const key of Object.keys(path)) {
|
|
155
|
+
const paramValue = path[key];
|
|
156
|
+
if (typeof paramValue === 'string' && paramValue.length > 0)
|
|
157
|
+
pathname = pathname.replace(`{${key}}`, paramValue);
|
|
158
|
+
}
|
|
159
|
+
const searchParams = new URLSearchParams();
|
|
160
|
+
for (const key of Object.keys(query)) {
|
|
161
|
+
const paramValue = query[key];
|
|
162
|
+
if (typeof paramValue === 'string' && paramValue.length > 0)
|
|
163
|
+
searchParams.append(key, paramValue);
|
|
164
|
+
}
|
|
165
|
+
return searchParams.size > 0
|
|
166
|
+
? `${pathname}?${searchParams.toString()}`
|
|
167
|
+
: pathname;
|
|
168
|
+
}
|
|
169
|
+
function Route({ route, ...props }) {
|
|
170
|
+
const segments = route.split('/').filter((part) => part.length > 0);
|
|
171
|
+
return (_jsx("div", { ...props, className: cn('flex flex-row items-center gap-0.5 overflow-auto text-nowrap', props.className), children: segments.map((part, index) => (_jsxs(Fragment, { children: [_jsx("span", { className: "text-fd-muted-foreground", children: "/" }), part.startsWith('{') && part.endsWith('}') ? (_jsx("code", { className: "bg-fd-primary/10 text-fd-primary", children: part })) : (_jsx("code", { className: "text-fd-foreground", children: part }))] }, index))) }));
|
|
172
|
+
}
|
|
173
|
+
function FormHeader({ route, method, isLoading, }) {
|
|
174
|
+
return (_jsxs("div", { className: "flex flex-row items-center gap-2 text-sm", children: [_jsx(MethodLabel, { children: method }), _jsx(Route, { route: route, className: "flex-1" }), _jsx("button", { type: "submit", className: cn(buttonVariants({ color: 'primary', size: 'sm' }), 'px-3 py-1.5'), disabled: isLoading, children: "Send" })] }));
|
|
175
|
+
}
|
|
176
|
+
function DefaultResultDisplay({ data }) {
|
|
177
|
+
const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);
|
|
178
|
+
const { shikiOptions } = useApiContext();
|
|
179
|
+
return (_jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-fd-card p-4", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground", children: [_jsx(statusInfo.icon, { className: cn('size-4', statusInfo.color) }), statusInfo.description] }), _jsx("p", { className: "text-sm text-fd-muted-foreground", children: data.status }), data.data ? (_jsx(DynamicCodeBlock, { lang: typeof data.data === 'string' && data.data.length > 50000
|
|
180
|
+
? 'text'
|
|
181
|
+
: data.type, code: typeof data.data === 'string'
|
|
182
|
+
? data.data
|
|
183
|
+
: JSON.stringify(data.data, null, 2), ...shikiOptions })) : null] }));
|
|
184
|
+
}
|
|
185
|
+
export function CollapsiblePanel({ title, children, ...props }) {
|
|
186
|
+
return (_jsxs(Collapsible, { ...props, className: "border rounded-xl bg-fd-card text-fd-card-foreground overflow-hidden", children: [_jsxs(CollapsibleTrigger, { className: "group w-full inline-flex items-center gap-2 justify-between p-3 text-sm font-medium hover:bg-fd-accent", children: [title, _jsx(ChevronDown, { className: "size-4 group-data-[state=open]:rotate-180" })] }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "flex flex-col gap-4 p-3", children: children }) })] }));
|
|
187
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
import type { RequestSchema } from '../../render/playground';
|
|
3
|
+
type FieldOfType<Type> = Extract<RequestSchema, {
|
|
4
|
+
type: Type;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function ObjectInput({ field, fieldName, ...props }: {
|
|
7
|
+
field: FieldOfType<'object'>;
|
|
8
|
+
fieldName: string;
|
|
9
|
+
} & HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function FieldInput({ field, fieldName, ...props }: HTMLAttributes<HTMLElement> & {
|
|
11
|
+
field: Exclude<RequestSchema, {
|
|
12
|
+
type: 'switcher';
|
|
13
|
+
}>;
|
|
14
|
+
fieldName: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
16
|
+
export declare function FieldSet({ field, fieldName, toolbar, name, ...props }: HTMLAttributes<HTMLElement> & {
|
|
17
|
+
name?: string;
|
|
18
|
+
field: RequestSchema;
|
|
19
|
+
fieldName: string;
|
|
20
|
+
toolbar?: ReactNode;
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=inputs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../../src/ui/playground/inputs.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAWf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMzD,KAAK,WAAW,CAAC,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AA6BhE,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE;IACD,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,cAAc,CAAC,cAAc,CAAC,2CAqBjC;AAoJD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG;IAC/B,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;CACnB,kDAuFA;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,SAAS,EACT,OAAO,EACP,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB,kDA8EA"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, } from 'react';
|
|
3
|
+
import { Plus, Trash2 } from 'lucide-react';
|
|
4
|
+
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
|
|
5
|
+
import { cn, buttonVariants } from 'fumadocs-ui/components/api';
|
|
6
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../ui/components/select';
|
|
7
|
+
import { resolve } from '../../ui/playground/resolve';
|
|
8
|
+
import { Input, labelVariants } from '../../ui/components/input';
|
|
9
|
+
import { getDefaultValue } from '../../ui/playground/get-default-values';
|
|
10
|
+
import { useSchemaContext } from '../../ui/contexts/schema';
|
|
11
|
+
function FieldHeader({ name, required = false, type, ...props }) {
|
|
12
|
+
return (_jsxs("label", { ...props, className: cn('w-full inline-flex items-center gap-1', props.className), children: [_jsx("span", { className: cn(labelVariants()), children: name }), required ? _jsx("span", { className: "text-red-500", children: "*" }) : null, _jsx("div", { className: "flex-1" }), type ? (_jsx("code", { className: "text-xs text-fd-muted-foreground", children: type })) : null, props.children] }));
|
|
13
|
+
}
|
|
14
|
+
export function ObjectInput({ field, fieldName, ...props }) {
|
|
15
|
+
const { references } = useSchemaContext();
|
|
16
|
+
return (_jsxs("div", { ...props, className: cn('flex flex-col gap-6', props.className), children: [Object.entries(field.properties).map(([key, child]) => (_jsx(FieldSet, { name: key, field: resolve(child, references), fieldName: `${fieldName}.${key}` }, key))), field.additionalProperties ? (_jsx(AdditionalProperties, { fieldName: fieldName, type: field.additionalProperties })) : null] }));
|
|
17
|
+
}
|
|
18
|
+
function AdditionalProperties({ fieldName, type, }) {
|
|
19
|
+
const { control, setValue } = useFormContext();
|
|
20
|
+
const { references, dynamic } = useSchemaContext();
|
|
21
|
+
const [nextName, setNextName] = useState('');
|
|
22
|
+
const [properties, setProperties] = useState(() => {
|
|
23
|
+
const d = dynamic.current.get(`additional_${fieldName}`);
|
|
24
|
+
if (d?.type === 'object')
|
|
25
|
+
return d.properties;
|
|
26
|
+
return [];
|
|
27
|
+
});
|
|
28
|
+
dynamic.current.set(`additional_${fieldName}`, {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties,
|
|
31
|
+
});
|
|
32
|
+
const onAppend = () => {
|
|
33
|
+
const name = nextName.trim();
|
|
34
|
+
if (name.length === 0)
|
|
35
|
+
return;
|
|
36
|
+
setProperties((p) => {
|
|
37
|
+
if (p.includes(name))
|
|
38
|
+
return p;
|
|
39
|
+
setValue(`${fieldName}.${name}`, '');
|
|
40
|
+
setNextName('');
|
|
41
|
+
return [...p, name];
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const types = typeof type === 'string'
|
|
45
|
+
? resolveDynamicTypes(references[type], references)
|
|
46
|
+
: undefined;
|
|
47
|
+
return (_jsxs(_Fragment, { children: [properties.map((item) => (_jsx(FieldSet, { name: item, field: {
|
|
48
|
+
type: 'switcher',
|
|
49
|
+
items: types ?? anyFields,
|
|
50
|
+
isRequired: false,
|
|
51
|
+
}, fieldName: `${fieldName}.${item}`, toolbar: _jsx("button", { type: "button", "aria-label": "Remove Item", className: cn(buttonVariants({
|
|
52
|
+
color: 'secondary',
|
|
53
|
+
size: 'sm',
|
|
54
|
+
})), onClick: () => {
|
|
55
|
+
setProperties((p) => p.filter((prop) => prop !== item));
|
|
56
|
+
control.unregister(`${fieldName}.${item}`);
|
|
57
|
+
}, children: _jsx(Trash2, { className: "size-4" }) }) }, item))), _jsxs("div", { className: "flex flex-row gap-1", children: [_jsx(Input, { value: nextName, placeholder: "Enter Property Name", onChange: (e) => {
|
|
58
|
+
setNextName(e.target.value);
|
|
59
|
+
}, onKeyDown: (e) => {
|
|
60
|
+
if (e.key === 'Enter') {
|
|
61
|
+
onAppend();
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
}
|
|
64
|
+
} }), _jsx("button", { type: "button", className: cn(buttonVariants({ color: 'secondary' })), onClick: onAppend, children: "New" })] })] }));
|
|
65
|
+
}
|
|
66
|
+
function resolveDynamicTypes(schema, references) {
|
|
67
|
+
if (schema.type !== 'switcher')
|
|
68
|
+
return { [schema.type]: schema };
|
|
69
|
+
return Object.fromEntries(Object.entries(schema.items).map(([key, value]) => [
|
|
70
|
+
key,
|
|
71
|
+
resolve(value, references),
|
|
72
|
+
]));
|
|
73
|
+
}
|
|
74
|
+
const anyFields = {
|
|
75
|
+
string: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
isRequired: false,
|
|
78
|
+
defaultValue: '',
|
|
79
|
+
},
|
|
80
|
+
boolean: {
|
|
81
|
+
type: 'boolean',
|
|
82
|
+
isRequired: false,
|
|
83
|
+
defaultValue: '',
|
|
84
|
+
},
|
|
85
|
+
number: {
|
|
86
|
+
type: 'number',
|
|
87
|
+
isRequired: false,
|
|
88
|
+
defaultValue: '',
|
|
89
|
+
},
|
|
90
|
+
object: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {},
|
|
93
|
+
additionalProperties: true,
|
|
94
|
+
isRequired: false,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
anyFields.array = {
|
|
98
|
+
type: 'array',
|
|
99
|
+
isRequired: false,
|
|
100
|
+
items: {
|
|
101
|
+
type: 'switcher',
|
|
102
|
+
isRequired: false,
|
|
103
|
+
items: anyFields,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
export function FieldInput({ field, fieldName, ...props }) {
|
|
107
|
+
const { control, register } = useFormContext();
|
|
108
|
+
if (field.type === 'null')
|
|
109
|
+
return null;
|
|
110
|
+
if (field.type === 'object') {
|
|
111
|
+
return (_jsx(ObjectInput, { field: field, fieldName: fieldName, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-card p-3 shadow-sm', props.className) }));
|
|
112
|
+
}
|
|
113
|
+
if (field.type === 'array') {
|
|
114
|
+
return (_jsx(ArrayInput, { fieldName: fieldName, field: field, ...props, className: cn('rounded-lg border border-fd-primary/20 bg-fd-background p-3 shadow-sm', props.className) }));
|
|
115
|
+
}
|
|
116
|
+
if (field.type === 'file' || field.type === 'boolean') {
|
|
117
|
+
return (_jsx(Controller, { control: control, name: fieldName, render: ({ field: { value, onChange, ...restField } }) => field.type === 'file' ? (_jsx("input", { id: fieldName, type: "file", multiple: false, onChange: (e) => {
|
|
118
|
+
if (!e.target.files)
|
|
119
|
+
return;
|
|
120
|
+
onChange(e.target.files.item(0));
|
|
121
|
+
}, ...props, ...restField })) : (_jsxs(Select, { value: value, onValueChange: onChange, disabled: restField.disabled, children: [_jsx(SelectTrigger, { id: fieldName, className: props.className, ...restField, children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "true", children: "True" }), _jsx(SelectItem, { value: "false", children: "False" }), field.isRequired ? null : (_jsx(SelectItem, { value: "null", children: "Null" }))] })] })) }));
|
|
122
|
+
}
|
|
123
|
+
return (_jsx(Input, { id: fieldName, placeholder: "Enter value", type: field.type === 'string' ? 'text' : 'number', ...register(fieldName), ...props }));
|
|
124
|
+
}
|
|
125
|
+
export function FieldSet({ field, fieldName, toolbar, name, ...props }) {
|
|
126
|
+
const { references, dynamic } = useSchemaContext();
|
|
127
|
+
const [value, setValue] = useState(() => {
|
|
128
|
+
if (field.type !== 'switcher')
|
|
129
|
+
return '';
|
|
130
|
+
const d = dynamic.current.get(fieldName);
|
|
131
|
+
const items = Object.keys(field.items);
|
|
132
|
+
if (d?.type === 'field') {
|
|
133
|
+
// schemas are passed from server components, they shouldn't be re-constructed
|
|
134
|
+
const cached = items.find((item) => d.schema === field.items[item]);
|
|
135
|
+
if (cached)
|
|
136
|
+
return cached;
|
|
137
|
+
}
|
|
138
|
+
return items[0];
|
|
139
|
+
});
|
|
140
|
+
if (field.type === 'null')
|
|
141
|
+
return null;
|
|
142
|
+
if (value && field.type === 'switcher') {
|
|
143
|
+
dynamic.current.set(fieldName, {
|
|
144
|
+
type: 'field',
|
|
145
|
+
schema: field.items[value],
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (field.type === 'switcher') {
|
|
149
|
+
const child = resolve(field.items[value], references);
|
|
150
|
+
return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsxs(FieldHeader, { name: name, htmlFor: fieldName, required: field.isRequired, children: [_jsx("select", { value: value, onChange: (e) => setValue(e.target.value), className: "text-xs", children: Object.keys(field.items).map((item) => (_jsx("option", { value: item, children: item }, item))) }), toolbar] }), _jsx("p", { className: "text-xs text-fd-muted-foreground", children: field.description }), child.type === 'switcher' ? (_jsx(FieldSet, { field: child, fieldName: fieldName })) : (_jsx(FieldInput, { field: child, fieldName: fieldName }))] }));
|
|
151
|
+
}
|
|
152
|
+
return (_jsxs("fieldset", { ...props, className: cn('flex flex-col gap-1.5', props.className), children: [_jsx(FieldHeader, { htmlFor: fieldName, name: name, required: field.isRequired, type: field.type, children: toolbar }), _jsx(FieldInput, { field: field, fieldName: fieldName })] }));
|
|
153
|
+
}
|
|
154
|
+
function ArrayInput({ fieldName, field, ...props }) {
|
|
155
|
+
const { references } = useSchemaContext();
|
|
156
|
+
const items = resolve(field.items, references);
|
|
157
|
+
const { fields, append, remove } = useFieldArray({
|
|
158
|
+
name: fieldName,
|
|
159
|
+
});
|
|
160
|
+
return (_jsxs("div", { ...props, className: cn('flex flex-col gap-2', props.className), children: [fields.map((item, index) => (_jsx(FieldSet, { name: `${fieldName.split('.').at(-1)}[${index}]`, field: items, fieldName: `${fieldName}.${index}`, toolbar: _jsx("button", { type: "button", "aria-label": "Remove Item", className: cn(buttonVariants({
|
|
161
|
+
color: 'secondary',
|
|
162
|
+
size: 'sm',
|
|
163
|
+
})), onClick: () => {
|
|
164
|
+
remove(index);
|
|
165
|
+
}, children: _jsx(Trash2, { className: "size-4" }) }) }, item.id))), _jsxs("button", { type: "button", className: cn(buttonVariants({
|
|
166
|
+
color: 'outline',
|
|
167
|
+
className: 'gap-1.5 py-2',
|
|
168
|
+
size: 'sm',
|
|
169
|
+
})), onClick: () => {
|
|
170
|
+
append(getDefaultValue(items, references));
|
|
171
|
+
}, children: [_jsx(Plus, { className: "size-4" }), "New Item"] })] }));
|
|
172
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ReferenceSchema, type RequestSchema } from '../../render/playground';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve reference
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolve(schema: RequestSchema | ReferenceSchema | string, references: Record<string, RequestSchema>): RequestSchema;
|
|
6
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/ui/playground/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;GAEG;AACH,wBAAgB,OAAO,CACrB,MAAM,EAAE,aAAa,GAAG,eAAe,GAAG,MAAM,EAChD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GACxC,aAAa,CASf"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve reference
|
|
3
|
+
*/
|
|
4
|
+
export function resolve(schema, references) {
|
|
5
|
+
if (typeof schema === 'string')
|
|
6
|
+
return references[schema];
|
|
7
|
+
if (schema.type !== 'ref')
|
|
8
|
+
return schema;
|
|
9
|
+
return {
|
|
10
|
+
...references[schema.schema],
|
|
11
|
+
description: schema.description,
|
|
12
|
+
isRequired: schema.isRequired,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-info.d.ts","sourceRoot":"","sources":["../../../src/ui/playground/status-info.tsx"],"names":[],"mappings":"AAEA,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC;CACzB;AAsBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBxD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CircleCheckIcon, CircleXIcon } from 'lucide-react';
|
|
2
|
+
const statusMap = {
|
|
3
|
+
400: { description: 'Bad Request', color: 'text-red-500', icon: CircleXIcon },
|
|
4
|
+
401: {
|
|
5
|
+
description: 'Unauthorized',
|
|
6
|
+
color: 'text-red-500',
|
|
7
|
+
icon: CircleXIcon,
|
|
8
|
+
},
|
|
9
|
+
403: { description: 'Forbidden', color: 'text-red-500', icon: CircleXIcon },
|
|
10
|
+
404: {
|
|
11
|
+
description: 'Not Found',
|
|
12
|
+
color: 'text-fd-muted-foreground',
|
|
13
|
+
icon: CircleXIcon,
|
|
14
|
+
},
|
|
15
|
+
500: {
|
|
16
|
+
description: 'Internal Server Error',
|
|
17
|
+
color: 'text-red-500',
|
|
18
|
+
icon: CircleXIcon,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export function getStatusInfo(status) {
|
|
22
|
+
if (status in statusMap) {
|
|
23
|
+
return statusMap[status];
|
|
24
|
+
}
|
|
25
|
+
if (status >= 200 && status < 300) {
|
|
26
|
+
return {
|
|
27
|
+
description: 'Successful',
|
|
28
|
+
color: 'text-green-500',
|
|
29
|
+
icon: CircleCheckIcon,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (status >= 400) {
|
|
33
|
+
return { description: 'Error', color: 'text-red-500', icon: CircleXIcon };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
description: 'No Description',
|
|
37
|
+
color: 'text-fd-muted-foreground',
|
|
38
|
+
icon: CircleXIcon,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-select.d.ts","sourceRoot":"","sources":["../../src/ui/server-select.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,cAAc,CAAC,kDA6EzE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useApiContext, useServerSelectContext } from '../ui/contexts/api';
|
|
4
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select';
|
|
5
|
+
import { Input, labelVariants } from '../ui/components/input';
|
|
6
|
+
import { cn } from 'fumadocs-ui/components/api';
|
|
7
|
+
export default function ServerSelect(props) {
|
|
8
|
+
const { servers } = useApiContext();
|
|
9
|
+
const { server, setServer, setServerVariables } = useServerSelectContext();
|
|
10
|
+
if (servers.length <= 1)
|
|
11
|
+
return null;
|
|
12
|
+
const schema = server
|
|
13
|
+
? servers.find((item) => item.url === server.url)
|
|
14
|
+
: undefined;
|
|
15
|
+
return (_jsxs("div", { ...props, className: cn('flex flex-col gap-4', props.className), children: [_jsxs(Select, { value: server?.url, onValueChange: setServer, children: [_jsx(SelectTrigger, { className: "h-auto break-all", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: servers.map((item) => (_jsxs(SelectItem, { value: item.url, children: [item.url, _jsx("p", { className: "text-start text-fd-muted-foreground", children: item.description })] }, item.url))) })] }), Object.entries(schema?.variables ?? {}).map(([key, variable]) => {
|
|
16
|
+
if (!server)
|
|
17
|
+
return;
|
|
18
|
+
const id = `fd_server_select_${key}`;
|
|
19
|
+
return (_jsxs("fieldset", { className: "flex flex-col gap-1", children: [_jsx("label", { className: cn(labelVariants()), htmlFor: id, children: key }), _jsx("p", { className: "text-xs text-fd-muted-foreground empty:hidden", children: variable.description }), variable.enum ? (_jsxs(Select, { value: server.variables[key], onValueChange: (v) => setServerVariables({
|
|
20
|
+
...server?.variables,
|
|
21
|
+
[key]: v,
|
|
22
|
+
}), children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: variable.enum.map((value) => (_jsx(SelectItem, { value: value, children: value }, value))) })] })) : (_jsx(Input, { id: id, value: server.variables[key], onChange: (e) => setServerVariables({
|
|
23
|
+
...server?.variables,
|
|
24
|
+
[key]: e.target.value,
|
|
25
|
+
}) }))] }, key));
|
|
26
|
+
})] }));
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combine-schema.d.ts","sourceRoot":"","sources":["../../src/utils/combine-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAoDlE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combine multiple object schemas into one
|
|
3
|
+
*/
|
|
4
|
+
export function combineSchema(schema) {
|
|
5
|
+
const result = {
|
|
6
|
+
type: undefined,
|
|
7
|
+
};
|
|
8
|
+
function add(s) {
|
|
9
|
+
if (s.type) {
|
|
10
|
+
result.type ?? (result.type = []);
|
|
11
|
+
if (!Array.isArray(result.type)) {
|
|
12
|
+
result.type = [result.type];
|
|
13
|
+
}
|
|
14
|
+
for (const v of Array.isArray(s.type) ? s.type : [s.type]) {
|
|
15
|
+
if (!result.type.includes(v)) {
|
|
16
|
+
result.type.push(v);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (s.properties) {
|
|
21
|
+
result.properties ?? (result.properties = {});
|
|
22
|
+
Object.assign(result.properties, s.properties);
|
|
23
|
+
}
|
|
24
|
+
if (s.additionalProperties === true) {
|
|
25
|
+
result.additionalProperties = true;
|
|
26
|
+
}
|
|
27
|
+
else if (s.additionalProperties &&
|
|
28
|
+
typeof result.additionalProperties !== 'boolean') {
|
|
29
|
+
result.additionalProperties ?? (result.additionalProperties = {});
|
|
30
|
+
Object.assign(result.additionalProperties, s.additionalProperties);
|
|
31
|
+
}
|
|
32
|
+
if (s.required) {
|
|
33
|
+
result.required ?? (result.required = []);
|
|
34
|
+
result.required.push(...s.required);
|
|
35
|
+
}
|
|
36
|
+
if (s.enum && s.enum.length > 0) {
|
|
37
|
+
result.enum ?? (result.enum = []);
|
|
38
|
+
result.enum.push(...s.enum);
|
|
39
|
+
}
|
|
40
|
+
if (s.allOf) {
|
|
41
|
+
s.allOf.forEach(add);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
schema.forEach(add);
|
|
45
|
+
return result;
|
|
46
|
+
}
|