zudoku 0.0.0-f5761c9 → 0.0.0-ff3bc72
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/config/validators/validate.d.ts +14 -10
- package/dist/config/validators/validate.js +1 -0
- package/dist/config/validators/validate.js.map +1 -1
- package/dist/lib/authentication/state.d.ts +16 -0
- package/dist/lib/authentication/state.js +5 -0
- package/dist/lib/authentication/state.js.map +1 -1
- package/dist/lib/components/Banner.js +7 -1
- package/dist/lib/components/Banner.js.map +1 -1
- package/dist/lib/components/ErrorPage.js +1 -2
- package/dist/lib/components/ErrorPage.js.map +1 -1
- package/dist/lib/components/InlineCode.d.ts +2 -1
- package/dist/lib/components/InlineCode.js +9 -1
- package/dist/lib/components/InlineCode.js.map +1 -1
- package/dist/lib/components/Layout.js +1 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/core/DevPortalContext.d.ts +1 -1
- package/dist/lib/oas/graphql/index.js +12 -6
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/oas/parser/index.d.ts +1 -0
- package/dist/lib/oas/parser/index.js.map +1 -1
- package/dist/lib/plugins/openapi/Endpoint.d.ts +1 -3
- package/dist/lib/plugins/openapi/Endpoint.js +46 -8
- package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +1 -1
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.d.ts +2 -1
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +2 -2
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +14 -3
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/SimpleSelect.d.ts +2 -1
- package/dist/lib/plugins/openapi/SimpleSelect.js +1 -1
- package/dist/lib/plugins/openapi/SimpleSelect.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/gql.d.ts +10 -2
- package/dist/lib/plugins/openapi/graphql/gql.js +2 -1
- package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/graphql.d.ts +26 -0
- package/dist/lib/plugins/openapi/graphql/graphql.js +87 -0
- package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +2 -1
- package/dist/lib/plugins/openapi/playground/Playground.js +13 -5
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/ResponseTab.js +1 -1
- package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +1 -1
- package/dist/vite/config.js +12 -12
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/plugin-frontmatter.d.ts +2 -0
- package/dist/vite/plugin-frontmatter.js +30 -0
- package/dist/vite/plugin-frontmatter.js.map +1 -0
- package/dist/vite/plugin-sidebar.js +14 -1
- package/dist/vite/plugin-sidebar.js.map +1 -1
- package/dist/vite/plugin.js +2 -2
- package/dist/vite/plugin.js.map +1 -1
- package/lib/{CategoryHeading-EN3W3xEN.js → CategoryHeading-ovR-zHRq.js} +2 -2
- package/lib/{CategoryHeading-EN3W3xEN.js.map → CategoryHeading-ovR-zHRq.js.map} +1 -1
- package/lib/{DeveloperHint-CZ4VwuKw.js → DeveloperHint-YeWHKvyr.js} +2 -2
- package/lib/{DeveloperHint-CZ4VwuKw.js.map → DeveloperHint-YeWHKvyr.js.map} +1 -1
- package/lib/ErrorPage-CsZAN_za.js +16 -0
- package/lib/ErrorPage-CsZAN_za.js.map +1 -0
- package/lib/{Input-DulGxZh-.js → Input-CtVUl3eT.js} +3 -3
- package/lib/{Input-DulGxZh-.js.map → Input-CtVUl3eT.js.map} +1 -1
- package/lib/{Markdown-BUUIyZbc.js → Markdown-DapSf3wG.js} +8 -2
- package/lib/{Markdown-BUUIyZbc.js.map → Markdown-DapSf3wG.js.map} +1 -1
- package/lib/{MdxPage-COBmXj_4.js → MdxPage-BqBWsXZ1.js} +3 -3
- package/lib/{MdxPage-COBmXj_4.js.map → MdxPage-BqBWsXZ1.js.map} +1 -1
- package/lib/{OperationList-BwJXexkA.js → OperationList-CYrmxPa8.js} +150 -108
- package/lib/OperationList-CYrmxPa8.js.map +1 -0
- package/lib/{Route-CX_-Q1HO.js → Route-Q5mqNQrv.js} +2 -2
- package/lib/{Route-CX_-Q1HO.js.map → Route-Q5mqNQrv.js.map} +1 -1
- package/lib/{SidebarBadge-gvlvsv3E.js → SidebarBadge-Dx7jtnoA.js} +3 -3
- package/lib/{SidebarBadge-gvlvsv3E.js.map → SidebarBadge-Dx7jtnoA.js.map} +1 -1
- package/lib/{SlotletProvider-CULK8zmk.js → SlotletProvider-D3UD5Go3.js} +4 -4
- package/lib/{SlotletProvider-CULK8zmk.js.map → SlotletProvider-D3UD5Go3.js.map} +1 -1
- package/lib/assets/{worker-DgVH8VJc.js → worker-BP8Uzflt.js} +1293 -1286
- package/lib/assets/{worker-DgVH8VJc.js.map → worker-BP8Uzflt.js.map} +1 -1
- package/lib/{index-BuA1OA5H.js → index-BlJ2rj99.js} +1770 -1643
- package/lib/index-BlJ2rj99.js.map +1 -0
- package/lib/{index-Q0TPJvr8.js → index-BngPzhKn.js} +3 -3
- package/lib/{index-Q0TPJvr8.js.map → index-BngPzhKn.js.map} +1 -1
- package/lib/{index-BfA1oLPP.js → index-Dolisrci.js} +3 -3
- package/lib/{index-BfA1oLPP.js.map → index-Dolisrci.js.map} +1 -1
- package/lib/state-hNe1dw4B.js +548 -0
- package/lib/state-hNe1dw4B.js.map +1 -0
- package/lib/zudoku.auth-auth0.js +1 -1
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +4 -4
- package/lib/zudoku.components.js +470 -466
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.openapi-worker.js +1617 -1610
- package/lib/zudoku.openapi-worker.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +5 -5
- package/lib/zudoku.plugin-custom-page.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +4 -4
- package/package.json +10 -1
- package/src/lib/authentication/state.ts +17 -0
- package/src/lib/components/Banner.tsx +12 -2
- package/src/lib/components/ErrorPage.tsx +0 -2
- package/src/lib/components/InlineCode.tsx +10 -0
- package/src/lib/components/Layout.tsx +1 -1
- package/src/lib/core/DevPortalContext.ts +1 -1
- package/src/lib/oas/graphql/index.ts +15 -11
- package/src/lib/oas/parser/index.ts +1 -0
- package/src/lib/plugins/openapi/Endpoint.tsx +86 -22
- package/src/lib/plugins/openapi/OperationList.tsx +3 -1
- package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +3 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +17 -2
- package/src/lib/plugins/openapi/SimpleSelect.tsx +10 -2
- package/src/lib/plugins/openapi/graphql/gql.ts +11 -3
- package/src/lib/plugins/openapi/graphql/graphql.ts +113 -1
- package/src/lib/plugins/openapi/playground/Playground.tsx +39 -5
- package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -1
- package/dist/vite/plugin-icons.d.ts +0 -3
- package/dist/vite/plugin-icons.js +0 -47
- package/dist/vite/plugin-icons.js.map +0 -1
- package/lib/ErrorPage-C5Pnyfbg.js +0 -18
- package/lib/ErrorPage-C5Pnyfbg.js.map +0 -1
- package/lib/OperationList-BwJXexkA.js.map +0 -1
- package/lib/index-BuA1OA5H.js.map +0 -1
- package/lib/state-BUM4jc0J.js +0 -288
- package/lib/state-BUM4jc0J.js.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-B6kdoens.js";
|
|
2
|
-
import { S as x, R as f } from "./SlotletProvider-
|
|
3
|
-
import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-
|
|
2
|
+
import { S as x, R as f } from "./SlotletProvider-D3UD5Go3.js";
|
|
3
|
+
import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-CtVUl3eT.js";
|
|
4
4
|
import { a as N, L as u, O as I } from "./index-BG0g4WW0.js";
|
|
5
5
|
import { u as h, a as E, b as S } from "./ZudokuContext-cr-pTRY1.js";
|
|
6
|
-
import { B as l, m as A } from "./index-
|
|
7
|
-
import { D as C } from "./DeveloperHint-
|
|
6
|
+
import { B as l, m as A } from "./index-Dolisrci.js";
|
|
7
|
+
import { D as C } from "./DeveloperHint-YeWHKvyr.js";
|
|
8
8
|
import { RotateCwIcon as P, TrashIcon as D, EyeOffIcon as R, EyeIcon as q, CheckIcon as O, CopyIcon as z } from "lucide-react";
|
|
9
9
|
import { useState as p } from "react";
|
|
10
|
-
import { a as T } from "./Markdown-
|
|
10
|
+
import { a as T } from "./Markdown-DapSf3wG.js";
|
|
11
11
|
function c(t, s) {
|
|
12
12
|
if (t)
|
|
13
13
|
return;
|
|
@@ -6,7 +6,7 @@ const x = (t, e, n) => Object.entries(t).flatMap(([a, p]) => {
|
|
|
6
6
|
return s ? {
|
|
7
7
|
path: s,
|
|
8
8
|
lazy: async () => {
|
|
9
|
-
const { MdxPage: i } = await import("./MdxPage-
|
|
9
|
+
const { MdxPage: i } = await import("./MdxPage-BqBWsXZ1.js"), { default: m, ...l } = await p();
|
|
10
10
|
return {
|
|
11
11
|
element: /* @__PURE__ */ u.jsx(
|
|
12
12
|
i,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./jsx-runtime-B6kdoens.js";
|
|
2
|
-
import { o as u } from "./index-
|
|
2
|
+
import { o as u } from "./index-BlJ2rj99.js";
|
|
3
3
|
import "./urql-YhcsXYy8.js";
|
|
4
4
|
import "./ZudokuContext-cr-pTRY1.js";
|
|
5
5
|
import "lucide-react";
|
|
6
6
|
import "zudoku/openapi-worker";
|
|
7
|
-
import "./index-
|
|
8
|
-
import "./ErrorPage-
|
|
9
|
-
import "./Markdown-
|
|
7
|
+
import "./index-Dolisrci.js";
|
|
8
|
+
import "./ErrorPage-CsZAN_za.js";
|
|
9
|
+
import "./Markdown-DapSf3wG.js";
|
|
10
10
|
import "./joinPath-B7kNnUX4.js";
|
|
11
11
|
import "./router-D2p7Olpn.js";
|
|
12
12
|
import "./index-BG0g4WW0.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-ff3bc72",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"homepage": "https://zudoku.dev",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/zuplo/zudoku.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/zuplo/zudoku/issues"
|
|
12
|
+
},
|
|
13
|
+
"description": "Framework for building high quality, interactive API documentation.",
|
|
5
14
|
"files": [
|
|
6
15
|
"dist",
|
|
7
16
|
"lib",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { create } from "zustand";
|
|
2
|
+
import { persist } from "zustand/middleware";
|
|
2
3
|
|
|
3
4
|
export const useAuthState = create<AuthState>(() => ({
|
|
4
5
|
isPending: false,
|
|
@@ -19,3 +20,19 @@ export interface UserProfile {
|
|
|
19
20
|
pictureUrl: string | undefined;
|
|
20
21
|
[key: string]: string | boolean | undefined;
|
|
21
22
|
}
|
|
23
|
+
|
|
24
|
+
interface SelectedServerState {
|
|
25
|
+
selectedServer?: string;
|
|
26
|
+
setSelectedServer: (newServer: string) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const useSelectedServerStore = create<SelectedServerState>()(
|
|
30
|
+
persist(
|
|
31
|
+
(set) => ({
|
|
32
|
+
selectedServer: undefined,
|
|
33
|
+
setSelectedServer: (newServer: string) =>
|
|
34
|
+
set({ selectedServer: newServer }),
|
|
35
|
+
}),
|
|
36
|
+
{ name: "zudoku-selected-server" },
|
|
37
|
+
),
|
|
38
|
+
);
|
|
@@ -9,7 +9,7 @@ const COLOR_MAP = {
|
|
|
9
9
|
tip: "bg-green-600",
|
|
10
10
|
caution: "bg-orange-500",
|
|
11
11
|
danger: "bg-rose-500",
|
|
12
|
-
};
|
|
12
|
+
} as const;
|
|
13
13
|
|
|
14
14
|
export const Banner = () => {
|
|
15
15
|
const { page } = useZudoku();
|
|
@@ -19,12 +19,22 @@ export const Banner = () => {
|
|
|
19
19
|
return <style>{`:root { --banner-height: 0px; }`}</style>;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const mappedColor =
|
|
23
|
+
page.banner.color && page.banner.color in COLOR_MAP
|
|
24
|
+
? COLOR_MAP[page.banner.color as keyof typeof COLOR_MAP]
|
|
25
|
+
: !page.banner.color
|
|
26
|
+
? "bg-primary"
|
|
27
|
+
: undefined;
|
|
28
|
+
|
|
29
|
+
const style = !mappedColor ? { backgroundColor: page.banner.color } : {};
|
|
30
|
+
|
|
22
31
|
return (
|
|
23
32
|
<div
|
|
24
33
|
className={cn(
|
|
25
34
|
"relative text-primary-foreground text-sm font-medium px-4 py-2 flex gap-2 items-center",
|
|
26
|
-
|
|
35
|
+
mappedColor,
|
|
27
36
|
)}
|
|
37
|
+
style={style}
|
|
28
38
|
>
|
|
29
39
|
<div className="w-full">{page.banner.message}</div>
|
|
30
40
|
{page.banner.dismissible && (
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import { Link } from "react-router-dom";
|
|
3
2
|
import { CategoryHeading } from "./CategoryHeading.js";
|
|
4
3
|
import { Heading } from "./Heading.js";
|
|
5
4
|
import { ProseClasses } from "./Markdown.js";
|
|
@@ -22,7 +21,6 @@ export const ErrorPage = ({
|
|
|
22
21
|
</Heading>
|
|
23
22
|
)}
|
|
24
23
|
<p>{message}</p>
|
|
25
|
-
<Link to="/">Go back home</Link>
|
|
26
24
|
</div>
|
|
27
25
|
);
|
|
28
26
|
};
|
|
@@ -4,11 +4,21 @@ import { cn } from "../util/cn.js";
|
|
|
4
4
|
export const InlineCode = ({
|
|
5
5
|
className,
|
|
6
6
|
children,
|
|
7
|
+
selectOnClick,
|
|
7
8
|
}: {
|
|
8
9
|
className?: string;
|
|
9
10
|
children: ReactNode;
|
|
11
|
+
selectOnClick?: boolean;
|
|
10
12
|
}) => (
|
|
11
13
|
<code
|
|
14
|
+
onClick={(e) => {
|
|
15
|
+
if (!selectOnClick) return;
|
|
16
|
+
const selection = window.getSelection();
|
|
17
|
+
const range = document.createRange();
|
|
18
|
+
range.selectNodeContents(e.currentTarget);
|
|
19
|
+
selection?.removeAllRanges();
|
|
20
|
+
selection?.addRange(range);
|
|
21
|
+
}}
|
|
12
22
|
className={cn(
|
|
13
23
|
"font-mono border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 whitespace-nowrap",
|
|
14
24
|
className,
|
|
@@ -53,7 +53,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
53
53
|
<div className="w-full max-w-screen-2xl mx-auto px-10 lg:px-12">
|
|
54
54
|
<Suspense
|
|
55
55
|
fallback={
|
|
56
|
-
<main className="grid h-
|
|
56
|
+
<main className="grid h-[calc(100vh-var(--header-height))] place-items-center">
|
|
57
57
|
<Spinner />
|
|
58
58
|
</main>
|
|
59
59
|
}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type ParameterObject,
|
|
19
19
|
type PathsObject,
|
|
20
20
|
type SchemaObject,
|
|
21
|
+
type ServerObject,
|
|
21
22
|
type TagObject,
|
|
22
23
|
} from "../parser/index.js";
|
|
23
24
|
|
|
@@ -57,9 +58,10 @@ export const createOperationSlug = (
|
|
|
57
58
|
);
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
const cache = new LRUCache<string,
|
|
61
|
+
const cache = new LRUCache<string, OpenAPIDocument>({
|
|
61
62
|
ttl: 60 * 10 * 1000,
|
|
62
63
|
ttlAutopurge: true,
|
|
64
|
+
fetchMethod: (_key, _oldValue, { context }) => validate(context as string),
|
|
63
65
|
});
|
|
64
66
|
|
|
65
67
|
const builder = new SchemaBuilder<{
|
|
@@ -158,6 +160,13 @@ const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
|
|
|
158
160
|
}),
|
|
159
161
|
});
|
|
160
162
|
|
|
163
|
+
const ServerItem = builder.objectRef<ServerObject>("Server").implement({
|
|
164
|
+
fields: (t) => ({
|
|
165
|
+
url: t.exposeString("url"),
|
|
166
|
+
description: t.exposeString("description", { nullable: true }),
|
|
167
|
+
}),
|
|
168
|
+
});
|
|
169
|
+
|
|
161
170
|
const PathItem = builder
|
|
162
171
|
.objectRef<{
|
|
163
172
|
path: string;
|
|
@@ -371,6 +380,10 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
|
371
380
|
fields: (t) => ({
|
|
372
381
|
openapi: t.string({ resolve: (root) => root.openapi }),
|
|
373
382
|
url: t.string({ resolve: (root) => root.servers?.at(0)?.url ?? "/" }),
|
|
383
|
+
servers: t.field({
|
|
384
|
+
type: [ServerItem],
|
|
385
|
+
resolve: (root) => root.servers ?? [],
|
|
386
|
+
}),
|
|
374
387
|
title: t.string({ resolve: (root) => root.info.title }),
|
|
375
388
|
version: t.string({ resolve: (root) => root.info.version }),
|
|
376
389
|
description: t.string({
|
|
@@ -417,16 +430,7 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
|
417
430
|
|
|
418
431
|
const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
|
|
419
432
|
const hash = hashit(input);
|
|
420
|
-
|
|
421
|
-
if (cache.has(hash)) {
|
|
422
|
-
return cache.get(hash)!;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const schema = validate(input);
|
|
426
|
-
|
|
427
|
-
cache.set(hash, schema);
|
|
428
|
-
|
|
429
|
-
return schema;
|
|
433
|
+
return await cache.forceFetch(hash, { context: input });
|
|
430
434
|
};
|
|
431
435
|
|
|
432
436
|
const SchemaSource = builder.enumType("SchemaType", {
|
|
@@ -20,6 +20,7 @@ export type TagObject = DeepOmitReference<OpenAPIV3_1.TagObject>;
|
|
|
20
20
|
export type ExampleObject = DeepOmitReference<OpenAPIV3_1.ExampleObject>;
|
|
21
21
|
export type EncodingObject = DeepOmitReference<OpenAPIV3_1.EncodingObject>;
|
|
22
22
|
export type SchemaObject = DeepOmitReference<OpenAPIV3_1.SchemaObject>;
|
|
23
|
+
export type ServerObject = DeepOmitReference<OpenAPIV3_1.ServerObject>;
|
|
23
24
|
|
|
24
25
|
export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
|
|
25
26
|
|
|
@@ -1,31 +1,95 @@
|
|
|
1
1
|
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useState, useTransition } from "react";
|
|
3
|
+
import { useSelectedServerStore } from "../../authentication/state.js";
|
|
3
4
|
import { InlineCode } from "../../components/InlineCode.js";
|
|
5
|
+
import { Button } from "../../ui/Button.js";
|
|
6
|
+
import { useOasConfig } from "./context.js";
|
|
7
|
+
import { graphql } from "./graphql/index.js";
|
|
8
|
+
import { SimpleSelect } from "./SimpleSelect.js";
|
|
9
|
+
import { useQuery } from "./util/urql.js";
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
const ServersQuery = graphql(/* GraphQL */ `
|
|
12
|
+
query ServersQuery($input: JSON!, $type: SchemaType!) {
|
|
13
|
+
schema(input: $input, type: $type) {
|
|
14
|
+
url
|
|
15
|
+
servers {
|
|
16
|
+
url
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`);
|
|
21
|
+
|
|
22
|
+
const CopyButton = ({ url }: { url: string }) => {
|
|
6
23
|
const [isCopied, setIsCopied] = useState(false);
|
|
7
24
|
|
|
8
25
|
return (
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
<Button
|
|
27
|
+
onClick={() => {
|
|
28
|
+
void navigator.clipboard.writeText(url).then(() => {
|
|
29
|
+
setIsCopied(true);
|
|
30
|
+
setTimeout(() => setIsCopied(false), 2000);
|
|
31
|
+
});
|
|
32
|
+
}}
|
|
33
|
+
variant="ghost"
|
|
34
|
+
size="icon"
|
|
35
|
+
>
|
|
36
|
+
{isCopied ? (
|
|
37
|
+
<CheckIcon className="text-green-600" size={14} />
|
|
38
|
+
) : (
|
|
39
|
+
<CopyIcon size={14} strokeWidth={1.3} />
|
|
40
|
+
)}
|
|
41
|
+
</Button>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const context = { suspense: true } as const;
|
|
46
|
+
|
|
47
|
+
export const Endpoint = () => {
|
|
48
|
+
const [result] = useQuery({
|
|
49
|
+
query: ServersQuery,
|
|
50
|
+
variables: useOasConfig(),
|
|
51
|
+
context,
|
|
52
|
+
});
|
|
53
|
+
const [, startTransition] = useTransition();
|
|
54
|
+
const { selectedServer, setSelectedServer } = useSelectedServerStore();
|
|
55
|
+
|
|
56
|
+
if (!result.data) return null;
|
|
57
|
+
|
|
58
|
+
const { servers } = result.data.schema;
|
|
59
|
+
|
|
60
|
+
if (servers.length === 1) {
|
|
61
|
+
return (
|
|
62
|
+
<div className="flex items-center gap-2">
|
|
63
|
+
<span className="font-medium text-sm">Endpoint:</span>
|
|
64
|
+
<InlineCode className="text-xs px-2 py-1.5" selectOnClick>
|
|
65
|
+
{servers[0].url}
|
|
66
|
+
</InlineCode>
|
|
67
|
+
<CopyButton url={servers[0].url} />
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
74
|
+
<span className="font-medium text-sm">
|
|
75
|
+
{servers.length > 1 ? "Endpoints" : "Endpoint"}:
|
|
76
|
+
</span>
|
|
77
|
+
|
|
78
|
+
<SimpleSelect
|
|
79
|
+
className="font-mono text-xs bg-border/50 dark:bg-border/70 py-1.5 max-w-[450px] truncate"
|
|
80
|
+
onChange={(e) =>
|
|
81
|
+
startTransition(() => {
|
|
82
|
+
setSelectedServer(e.target.value);
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
value={selectedServer ?? result.data.schema.url}
|
|
86
|
+
showChevrons={servers.length > 1}
|
|
87
|
+
options={servers.map((server) => ({
|
|
88
|
+
value: server.url,
|
|
89
|
+
label: server.url,
|
|
90
|
+
}))}
|
|
91
|
+
/>
|
|
92
|
+
<CopyButton url={selectedServer ?? result.data.schema.url} />
|
|
29
93
|
</div>
|
|
30
94
|
);
|
|
31
95
|
};
|
|
@@ -133,7 +133,9 @@ export const OperationList = () => {
|
|
|
133
133
|
<Markdown content={result.data.schema.description ?? ""} />
|
|
134
134
|
</div>
|
|
135
135
|
<hr />
|
|
136
|
-
<
|
|
136
|
+
<div className="my-4 flex justify-end">
|
|
137
|
+
<Endpoint />
|
|
138
|
+
</div>
|
|
137
139
|
|
|
138
140
|
{result.data.schema.tags
|
|
139
141
|
.filter((tag) => tag.operations.length > 0)
|
|
@@ -3,9 +3,11 @@ import { PlaygroundDialog } from "./playground/PlaygroundDialog.js";
|
|
|
3
3
|
|
|
4
4
|
export const PlaygroundDialogWrapper = ({
|
|
5
5
|
server,
|
|
6
|
+
servers,
|
|
6
7
|
operation,
|
|
7
8
|
}: {
|
|
8
9
|
server: string;
|
|
10
|
+
servers?: string[];
|
|
9
11
|
operation: OperationListItemResult;
|
|
10
12
|
}) => {
|
|
11
13
|
const headers = operation.parameters
|
|
@@ -29,6 +31,7 @@ export const PlaygroundDialogWrapper = ({
|
|
|
29
31
|
return (
|
|
30
32
|
<PlaygroundDialog
|
|
31
33
|
server={server}
|
|
34
|
+
servers={servers}
|
|
32
35
|
method={operation.method}
|
|
33
36
|
url={operation.path}
|
|
34
37
|
headers={headers}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HTTPSnippet } from "@zudoku/httpsnippet";
|
|
2
2
|
import { Fragment, useMemo, useTransition } from "react";
|
|
3
3
|
import { useSearchParams } from "react-router-dom";
|
|
4
|
+
import { useSelectedServerStore } from "../../authentication/state.js";
|
|
4
5
|
import { TextColorMap } from "../../components/navigation/SidebarBadge.js";
|
|
5
6
|
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
6
7
|
import type { SchemaObject } from "../../oas/parser/index.js";
|
|
@@ -65,6 +66,9 @@ export const GetServerQuery = graphql(/* GraphQL */ `
|
|
|
65
66
|
query getServerQuery($input: JSON!, $type: SchemaType!) {
|
|
66
67
|
schema(input: $input, type: $type) {
|
|
67
68
|
url
|
|
69
|
+
servers {
|
|
70
|
+
url
|
|
71
|
+
}
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
`);
|
|
@@ -135,6 +139,8 @@ export const Sidecar = ({
|
|
|
135
139
|
);
|
|
136
140
|
});
|
|
137
141
|
|
|
142
|
+
const { selectedServer } = useSelectedServerStore();
|
|
143
|
+
|
|
138
144
|
const code = useMemo(() => {
|
|
139
145
|
const example = requestBodyContent?.[0]?.schema
|
|
140
146
|
? generateSchemaExample(requestBodyContent[0].schema as SchemaObject)
|
|
@@ -143,7 +149,7 @@ export const Sidecar = ({
|
|
|
143
149
|
const snippet = new HTTPSnippet({
|
|
144
150
|
method: operation.method.toLocaleUpperCase(),
|
|
145
151
|
url:
|
|
146
|
-
(result.data?.schema.url ?? "") +
|
|
152
|
+
(selectedServer ?? result.data?.schema.url ?? "") +
|
|
147
153
|
operation.path.replaceAll("{", ":").replaceAll("}", ""),
|
|
148
154
|
postData: example
|
|
149
155
|
? {
|
|
@@ -160,7 +166,13 @@ export const Sidecar = ({
|
|
|
160
166
|
});
|
|
161
167
|
|
|
162
168
|
return getConverted(snippet, selectedLang);
|
|
163
|
-
}, [
|
|
169
|
+
}, [
|
|
170
|
+
selectedServer,
|
|
171
|
+
selectedLang,
|
|
172
|
+
operation.method,
|
|
173
|
+
operation.path,
|
|
174
|
+
requestBodyContent,
|
|
175
|
+
]);
|
|
164
176
|
|
|
165
177
|
return (
|
|
166
178
|
<aside className="flex flex-col overflow-hidden sticky top-[--scroll-padding] gap-4">
|
|
@@ -175,6 +187,9 @@ export const Sidecar = ({
|
|
|
175
187
|
</span>
|
|
176
188
|
<PlaygroundDialogWrapper
|
|
177
189
|
server={result.data?.schema.url ?? ""}
|
|
190
|
+
servers={
|
|
191
|
+
result.data?.schema.servers.map((server) => server.url) ?? []
|
|
192
|
+
}
|
|
178
193
|
operation={operation}
|
|
179
194
|
/>
|
|
180
195
|
</SidecarBox.Head>
|
|
@@ -7,6 +7,7 @@ export const SimpleSelect = ({
|
|
|
7
7
|
onChange,
|
|
8
8
|
className,
|
|
9
9
|
options,
|
|
10
|
+
showChevrons = true,
|
|
10
11
|
}: {
|
|
11
12
|
value: string;
|
|
12
13
|
onChange: ChangeEventHandler<HTMLSelectElement>;
|
|
@@ -15,12 +16,14 @@ export const SimpleSelect = ({
|
|
|
15
16
|
value: string;
|
|
16
17
|
label: string;
|
|
17
18
|
}[];
|
|
19
|
+
showChevrons?: boolean;
|
|
18
20
|
}) => (
|
|
19
|
-
<div className=
|
|
21
|
+
<div className="grid">
|
|
20
22
|
<select
|
|
21
23
|
className={cn(
|
|
22
24
|
"row-start-1 col-start-1 border border-input text-foreground px-2 py-1 pe-6",
|
|
23
25
|
"rounded-md appearance-none bg-zinc-50 hover:bg-white dark:bg-zinc-800 hover:dark:bg-zinc-800/75",
|
|
26
|
+
className,
|
|
24
27
|
)}
|
|
25
28
|
value={value}
|
|
26
29
|
onChange={onChange}
|
|
@@ -31,7 +34,12 @@ export const SimpleSelect = ({
|
|
|
31
34
|
</option>
|
|
32
35
|
))}
|
|
33
36
|
</select>
|
|
34
|
-
<div
|
|
37
|
+
<div
|
|
38
|
+
className={cn(
|
|
39
|
+
!showChevrons && "hidden",
|
|
40
|
+
"row-start-1 col-start-1 self-center justify-self-end relative end-2 pointer-events-none",
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
35
43
|
<ChevronsUpDownIcon size={14} />
|
|
36
44
|
</div>
|
|
37
45
|
</div>
|
|
@@ -13,11 +13,13 @@ import * as types from "./graphql.js";
|
|
|
13
13
|
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
|
14
14
|
*/
|
|
15
15
|
const documents = {
|
|
16
|
+
"\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
|
|
17
|
+
types.ServersQueryDocument,
|
|
16
18
|
"\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n":
|
|
17
19
|
types.OperationsFragmentFragmentDoc,
|
|
18
20
|
"\n query AllOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n description\n title\n url\n version\n tags {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n }\n }\n }\n":
|
|
19
21
|
types.AllOperationsDocument,
|
|
20
|
-
"\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n }\n }\n":
|
|
22
|
+
"\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
|
|
21
23
|
types.GetServerQueryDocument,
|
|
22
24
|
"\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n tags {\n __typename\n name\n operations {\n __typename\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n }\n":
|
|
23
25
|
types.GetCategoriesDocument,
|
|
@@ -37,6 +39,12 @@ const documents = {
|
|
|
37
39
|
*/
|
|
38
40
|
export function graphql(source: string): unknown;
|
|
39
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
44
|
+
*/
|
|
45
|
+
export function graphql(
|
|
46
|
+
source: "\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n",
|
|
47
|
+
): (typeof documents)["\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n"];
|
|
40
48
|
/**
|
|
41
49
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
42
50
|
*/
|
|
@@ -53,8 +61,8 @@ export function graphql(
|
|
|
53
61
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
54
62
|
*/
|
|
55
63
|
export function graphql(
|
|
56
|
-
source: "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n }\n }\n",
|
|
57
|
-
): (typeof documents)["\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n }\n }\n"];
|
|
64
|
+
source: "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n",
|
|
65
|
+
): (typeof documents)["\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n"];
|
|
58
66
|
/**
|
|
59
67
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
60
68
|
*/
|