zudoku 0.28.0 → 0.28.1
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/app/main.js +1 -2
- package/dist/app/main.js.map +1 -1
- package/dist/config/validators/InputSidebarSchema.d.ts +2 -2
- package/dist/lib/components/PathRenderer.d.ts +11 -0
- package/dist/lib/components/PathRenderer.js +25 -0
- package/dist/lib/components/PathRenderer.js.map +1 -0
- package/dist/lib/components/ThemeSwitch.js +4 -4
- package/dist/lib/components/ThemeSwitch.js.map +1 -1
- package/dist/lib/components/index.d.ts +1 -0
- package/dist/lib/components/index.js +4 -2
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/components/navigation/SidebarCategory.js +16 -14
- package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
- package/dist/lib/oas/graphql/circular.js +17 -6
- package/dist/lib/oas/graphql/circular.js.map +1 -1
- package/dist/lib/plugins/openapi/ColorizedParam.js +3 -1
- package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +5 -10
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.js +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.js +7 -15
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/{SchemaComponents.js → SchemaPropertyItem.js} +10 -8
- package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -0
- package/dist/lib/plugins/openapi/schema/SchemaView.js +1 -1
- package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/utils.d.ts +1 -0
- package/dist/lib/plugins/openapi/schema/utils.js +2 -0
- package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
- package/dist/vite/plugin-api.js +4 -2
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/prerender.js +0 -1
- package/dist/vite/prerender.js.map +1 -1
- package/lib/{MdxPage-DewragjB.js → MdxPage-BuG8Tuwc.js} +2 -2
- package/lib/{MdxPage-DewragjB.js.map → MdxPage-BuG8Tuwc.js.map} +1 -1
- package/lib/{OperationList-D_ejrepA.js → OperationList-CDt1xdc4.js} +978 -970
- package/lib/OperationList-CDt1xdc4.js.map +1 -0
- package/lib/{circular-Dgpd6AN-.js → circular-DxaIIlWD.js} +251 -239
- package/lib/{circular-Dgpd6AN-.js.map → circular-DxaIIlWD.js.map} +1 -1
- package/lib/{createServer-BydbkTsd.js → createServer-CjNktZzL.js} +2 -2
- package/lib/{createServer-BydbkTsd.js.map → createServer-CjNktZzL.js.map} +1 -1
- package/lib/{index-DGugJOLc.js → index-Eb1oiHbM.js} +583 -560
- package/lib/index-Eb1oiHbM.js.map +1 -0
- package/lib/{useScrollToAnchor-eRM9tVvD.js → useScrollToAnchor-BZsGmBng.js} +84 -89
- package/lib/useScrollToAnchor-BZsGmBng.js.map +1 -0
- package/lib/zudoku.components.js +334 -317
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +1 -1
- package/package.json +1 -1
- package/src/app/main.tsx +1 -2
- package/src/lib/components/PathRenderer.tsx +59 -0
- package/src/lib/components/ThemeSwitch.tsx +15 -14
- package/src/lib/components/index.ts +7 -5
- package/src/lib/components/navigation/SidebarCategory.tsx +43 -41
- package/src/lib/oas/graphql/circular.ts +27 -6
- package/src/lib/plugins/openapi/ColorizedParam.tsx +3 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +6 -1
- package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -1
- package/src/lib/plugins/openapi/Sidecar.tsx +17 -26
- package/src/lib/plugins/openapi/playground/PathParams.tsx +1 -1
- package/src/lib/plugins/openapi/playground/Playground.tsx +23 -33
- package/src/lib/plugins/openapi/schema/{SchemaComponents.tsx → SchemaPropertyItem.tsx} +10 -6
- package/src/lib/plugins/openapi/schema/SchemaView.tsx +4 -1
- package/src/lib/plugins/openapi/schema/utils.ts +4 -0
- package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +0 -1
- package/lib/OperationList-D_ejrepA.js.map +0 -1
- package/lib/index-DGugJOLc.js.map +0 -1
- package/lib/useScrollToAnchor-eRM9tVvD.js.map +0 -1
- /package/dist/lib/plugins/openapi/schema/{SchemaComponents.d.ts → SchemaPropertyItem.d.ts} +0 -0
|
@@ -74,7 +74,7 @@ const C = (n) => ({
|
|
|
74
74
|
const h = {
|
|
75
75
|
path: r,
|
|
76
76
|
lazy: async () => {
|
|
77
|
-
const { MdxPage: l } = await import("./MdxPage-
|
|
77
|
+
const { MdxPage: l } = await import("./MdxPage-BuG8Tuwc.js"), { default: p, ...g } = await a();
|
|
78
78
|
return {
|
|
79
79
|
element: /* @__PURE__ */ P.jsx(
|
|
80
80
|
l,
|
package/package.json
CHANGED
package/src/app/main.tsx
CHANGED
|
@@ -11,12 +11,11 @@ import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
|
|
|
11
11
|
import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
|
|
12
12
|
import { configuredSidebar } from "virtual:zudoku-sidebar";
|
|
13
13
|
import "virtual:zudoku-theme.css";
|
|
14
|
-
import { Layout, RouterError, Zudoku } from "zudoku/components";
|
|
14
|
+
import { Layout, RouteGuard, RouterError, Zudoku } from "zudoku/components";
|
|
15
15
|
import type { ZudokuConfig } from "../config/config.js";
|
|
16
16
|
import { StatusPage } from "../lib/components/StatusPage.js";
|
|
17
17
|
import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
|
|
18
18
|
import { isNavigationPlugin } from "../lib/core/plugins.js";
|
|
19
|
-
import { RouteGuard } from "../lib/core/RouteGuard.js";
|
|
20
19
|
|
|
21
20
|
export const convertZudokuConfigToOptions = (
|
|
22
21
|
config: ZudokuConfig,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Fragment, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
type PathParamProps = {
|
|
4
|
+
name: string;
|
|
5
|
+
index: number;
|
|
6
|
+
originalValue?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const PathRenderer = ({
|
|
10
|
+
path,
|
|
11
|
+
renderParam,
|
|
12
|
+
}: {
|
|
13
|
+
path: string;
|
|
14
|
+
renderParam: (props: PathParamProps) => ReactNode;
|
|
15
|
+
}) =>
|
|
16
|
+
path.split("/").map((part, i, arr) => {
|
|
17
|
+
const matches = Array.from(part.matchAll(/{([^}]+)}/g));
|
|
18
|
+
const elements: ReactNode[] = [];
|
|
19
|
+
let lastIndex = 0;
|
|
20
|
+
|
|
21
|
+
matches.forEach((match, matchIndex) => {
|
|
22
|
+
const [originalValue, name] = match;
|
|
23
|
+
if (!name) return;
|
|
24
|
+
const startIndex = match.index!;
|
|
25
|
+
|
|
26
|
+
if (startIndex > lastIndex) {
|
|
27
|
+
elements.push(
|
|
28
|
+
<Fragment key={`text-${lastIndex}-${startIndex}`}>
|
|
29
|
+
{part.slice(lastIndex, startIndex)}
|
|
30
|
+
</Fragment>,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
elements.push(
|
|
35
|
+
<Fragment key={`param-${name}`}>
|
|
36
|
+
{renderParam({ name, originalValue, index: matchIndex })}
|
|
37
|
+
</Fragment>,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
lastIndex = startIndex + originalValue.length;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (lastIndex < part.length) {
|
|
44
|
+
elements.push(
|
|
45
|
+
<Fragment key={`text-${lastIndex}-${part.length}`}>
|
|
46
|
+
{part.slice(lastIndex)}
|
|
47
|
+
</Fragment>,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
53
|
+
<Fragment key={`${part}-${i}`}>
|
|
54
|
+
{elements}
|
|
55
|
+
{i < arr.length - 1 && "/"}
|
|
56
|
+
<wbr />
|
|
57
|
+
</Fragment>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { MoonStarIcon, SunIcon } from "lucide-react";
|
|
2
2
|
import { useTheme } from "next-themes";
|
|
3
3
|
import { Button } from "zudoku/ui/Button.js";
|
|
4
|
-
import {
|
|
4
|
+
import { ClientOnly } from "./ClientOnly.js";
|
|
5
5
|
|
|
6
6
|
export const ThemeSwitch = () => {
|
|
7
7
|
const { resolvedTheme, setTheme } = useTheme();
|
|
8
8
|
const ThemeIcon = resolvedTheme === "dark" ? MoonStarIcon : SunIcon;
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
|
-
<Button
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
<ClientOnly fallback={<Button variant="ghost" size="icon" />}>
|
|
12
|
+
<Button
|
|
13
|
+
variant="ghost"
|
|
14
|
+
size="icon"
|
|
15
|
+
aria-label={
|
|
16
|
+
resolvedTheme === "dark"
|
|
17
|
+
? "Switch to light mode"
|
|
18
|
+
: "Switch to dark mode"
|
|
19
|
+
}
|
|
20
|
+
onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
|
|
21
|
+
>
|
|
22
|
+
<ThemeIcon size={18} />
|
|
23
|
+
</Button>
|
|
24
|
+
</ClientOnly>
|
|
24
25
|
);
|
|
25
26
|
};
|
|
@@ -2,6 +2,7 @@ import { useMDXComponents as useMDXComponentsImport } from "@mdx-js/react";
|
|
|
2
2
|
import { Helmet } from "@zudoku/react-helmet-async";
|
|
3
3
|
import { Link as LinkImport } from "react-router";
|
|
4
4
|
import { useAuth as useAuthImport } from "../authentication/hook.js";
|
|
5
|
+
import { RouteGuard as RouteGuardImport } from "../core/RouteGuard.js";
|
|
5
6
|
import { RouterError as RouterErrorImport } from "../errors/RouterError.js";
|
|
6
7
|
import { ServerError as ServerErrorImport } from "../errors/ServerError.js";
|
|
7
8
|
import { Button as ButtonImport } from "../ui/Button.js";
|
|
@@ -10,16 +11,16 @@ import {
|
|
|
10
11
|
Bootstrap as BootstrapImport,
|
|
11
12
|
BootstrapStatic as BootstrapStaticImport,
|
|
12
13
|
} from "./Bootstrap.js";
|
|
13
|
-
import { ClientOnly as ClientOnlyImport } from "./ClientOnly.js";
|
|
14
|
-
import { Layout as LayoutImport } from "./Layout.js";
|
|
15
|
-
import { Markdown as MarkdownImport } from "./Markdown.js";
|
|
16
|
-
import { Spinner as SpinnerImport } from "./Spinner.js";
|
|
17
|
-
import { Zudoku as ZudokuImport } from "./Zudoku.js";
|
|
18
14
|
import {
|
|
19
15
|
CACHE_KEYS as CACHE_KEYS_IMPORT,
|
|
20
16
|
useCache as useCacheImport,
|
|
21
17
|
} from "./cache.js";
|
|
18
|
+
import { ClientOnly as ClientOnlyImport } from "./ClientOnly.js";
|
|
22
19
|
import { useZudoku as useZudokuImport } from "./context/ZudokuContext.js";
|
|
20
|
+
import { Layout as LayoutImport } from "./Layout.js";
|
|
21
|
+
import { Markdown as MarkdownImport } from "./Markdown.js";
|
|
22
|
+
import { Spinner as SpinnerImport } from "./Spinner.js";
|
|
23
|
+
import { Zudoku as ZudokuImport } from "./Zudoku.js";
|
|
23
24
|
|
|
24
25
|
export const useMDXComponents = /*@__PURE__*/ useMDXComponentsImport;
|
|
25
26
|
export const Layout = /*@__PURE__*/ LayoutImport;
|
|
@@ -27,6 +28,7 @@ export const RouterError = /*@__PURE__*/ RouterErrorImport;
|
|
|
27
28
|
export const ServerError = /*@__PURE__*/ ServerErrorImport;
|
|
28
29
|
export const Bootstrap = /*@__PURE__*/ BootstrapImport;
|
|
29
30
|
export const BootstrapStatic = /*@__PURE__*/ BootstrapStaticImport;
|
|
31
|
+
export const RouteGuard = /*@__PURE__*/ RouteGuardImport;
|
|
30
32
|
|
|
31
33
|
export const Head = /*@__PURE__*/ Helmet;
|
|
32
34
|
|
|
@@ -53,6 +53,22 @@ export const SidebarCategory = ({
|
|
|
53
53
|
</button>
|
|
54
54
|
);
|
|
55
55
|
|
|
56
|
+
const icon = category.icon && (
|
|
57
|
+
<category.icon
|
|
58
|
+
size={16}
|
|
59
|
+
className={cn("align-[-0.125em] ", isActive && "text-primary")}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const styles = navigationListItem({
|
|
64
|
+
className: [
|
|
65
|
+
"text-start font-medium",
|
|
66
|
+
isCollapsible || typeof category.link !== "undefined"
|
|
67
|
+
? "cursor-pointer"
|
|
68
|
+
: "cursor-default hover:bg-transparent",
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
|
|
56
72
|
return (
|
|
57
73
|
<Collapsible.Root
|
|
58
74
|
className="flex flex-col"
|
|
@@ -61,52 +77,38 @@ export const SidebarCategory = ({
|
|
|
61
77
|
onOpenChange={() => setOpen(true)}
|
|
62
78
|
>
|
|
63
79
|
<Collapsible.Trigger className="group" asChild disabled={!isCollapsible}>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{category.link?.type === "doc" ? (
|
|
83
|
-
<NavLink
|
|
84
|
-
to={joinPath(category.link.id)}
|
|
85
|
-
className="flex-1 truncate"
|
|
86
|
-
onClick={() => {
|
|
87
|
-
// if it is the current path and closed then open it because there's no path change to trigger the open
|
|
88
|
-
if (isActive && !open) {
|
|
89
|
-
setOpen(true);
|
|
90
|
-
}
|
|
91
|
-
}}
|
|
80
|
+
{category.link?.type === "doc" ? (
|
|
81
|
+
<NavLink
|
|
82
|
+
to={joinPath(category.link.id)}
|
|
83
|
+
className={styles}
|
|
84
|
+
onClick={() => {
|
|
85
|
+
setHasInteracted(true);
|
|
86
|
+
// if it is the current path and closed then open it because there's no path change to trigger the open
|
|
87
|
+
if (isActive && !open) {
|
|
88
|
+
setOpen(true);
|
|
89
|
+
}
|
|
90
|
+
}}
|
|
91
|
+
>
|
|
92
|
+
{icon}
|
|
93
|
+
<div
|
|
94
|
+
className={cn(
|
|
95
|
+
"flex items-center gap-2 justify-between w-full",
|
|
96
|
+
isActive ? "text-primary" : "text-foreground/80",
|
|
97
|
+
)}
|
|
92
98
|
>
|
|
93
|
-
<div
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{ToggleButton}
|
|
101
|
-
</div>
|
|
102
|
-
</NavLink>
|
|
103
|
-
) : (
|
|
99
|
+
<div className="truncate">{category.label}</div>
|
|
100
|
+
{ToggleButton}
|
|
101
|
+
</div>
|
|
102
|
+
</NavLink>
|
|
103
|
+
) : (
|
|
104
|
+
<div onClick={() => setHasInteracted(true)} className={styles}>
|
|
105
|
+
{icon}
|
|
104
106
|
<div className="flex items-center justify-between w-full">
|
|
105
107
|
<div className="flex gap-2 truncate w-full">{category.label}</div>
|
|
106
108
|
{ToggleButton}
|
|
107
109
|
</div>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
110
112
|
</Collapsible.Trigger>
|
|
111
113
|
<Collapsible.Content
|
|
112
114
|
className={cn(
|
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
import { GraphQLJSON } from "graphql-type-json";
|
|
2
2
|
import { GraphQLScalarType } from "graphql/index.js";
|
|
3
|
+
import { RecordAny } from "../../util/traverse.js";
|
|
3
4
|
|
|
4
5
|
export const CIRCULAR_REF = "$[Circular Reference]";
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
const handleCircularRefs = (
|
|
8
|
+
obj: any,
|
|
9
|
+
visited = new Map<string, string[]>(),
|
|
10
|
+
path: string[] = [],
|
|
11
|
+
): any => {
|
|
6
12
|
if (obj === CIRCULAR_REF) return CIRCULAR_REF;
|
|
7
13
|
if (obj === null || typeof obj !== "object") return obj;
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
const currentPath = path.join(".");
|
|
16
|
+
|
|
17
|
+
if (obj.type === "object" && obj.properties) {
|
|
18
|
+
const schemaKey = Object.keys(obj.properties).sort().join("-");
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
if (visited.has(schemaKey)) {
|
|
21
|
+
const prevPaths = visited.get(schemaKey)!;
|
|
22
|
+
if (prevPaths.some((prev) => currentPath.startsWith(prev))) {
|
|
23
|
+
return CIRCULAR_REF;
|
|
24
|
+
}
|
|
25
|
+
visited.set(schemaKey, [...prevPaths, currentPath]);
|
|
26
|
+
} else {
|
|
27
|
+
visited.set(schemaKey, [currentPath]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
|
|
13
31
|
if (Array.isArray(obj)) {
|
|
14
|
-
return obj.map((item) =>
|
|
32
|
+
return obj.map((item, index) =>
|
|
33
|
+
handleCircularRefs(item, visited, [...path, `${index}`]),
|
|
34
|
+
);
|
|
15
35
|
}
|
|
16
36
|
|
|
17
|
-
const result:
|
|
37
|
+
const result: RecordAny = {};
|
|
18
38
|
for (const [key, value] of Object.entries(obj)) {
|
|
19
|
-
result[key] = handleCircularRefs(value, visited);
|
|
39
|
+
result[key] = handleCircularRefs(value, visited, [...path, key]);
|
|
20
40
|
}
|
|
21
41
|
return result;
|
|
22
42
|
};
|
|
43
|
+
|
|
23
44
|
export const GraphQLJSONSchema = new GraphQLScalarType({
|
|
24
45
|
...GraphQLJSON,
|
|
25
46
|
name: "JSONSchema",
|
|
@@ -89,10 +89,10 @@ export const ColorizedParam = ({
|
|
|
89
89
|
<span
|
|
90
90
|
{...{ [DATA_ATTR]: normalizedSlug }}
|
|
91
91
|
className={cn(
|
|
92
|
-
|
|
93
|
-
"rounded-lg",
|
|
92
|
+
// This may not contain (inline-)flex or (inline-)block otherwise it breaks the browser's full text search
|
|
93
|
+
"relative rounded transition-all duration-100 rounded-lg",
|
|
94
94
|
"border border-[--border-color] p-0.5 text-[--param-color] bg-[--background-color]",
|
|
95
|
-
"data-[active=true]:border-[--param-color] data-[active=true]:shadow data-[active=true]
|
|
95
|
+
"data-[active=true]:border-[--param-color] data-[active=true]:shadow data-[active=true]:bottom-px",
|
|
96
96
|
className,
|
|
97
97
|
)}
|
|
98
98
|
title={title}
|
|
@@ -37,7 +37,12 @@ export const OperationListItem = ({
|
|
|
37
37
|
className="grid grid-cols-1 lg:grid-cols-[minmax(0,4fr)_minmax(0,3fr)] gap-8 items-start border-b-2 mb-16 pb-16"
|
|
38
38
|
>
|
|
39
39
|
<div className="flex flex-col gap-4">
|
|
40
|
-
<Heading
|
|
40
|
+
<Heading
|
|
41
|
+
level={2}
|
|
42
|
+
id={operation.slug}
|
|
43
|
+
registerSidebarAnchor
|
|
44
|
+
className="break-all"
|
|
45
|
+
>
|
|
41
46
|
{operation.summary}
|
|
42
47
|
</Heading>
|
|
43
48
|
<div className="text-sm flex gap-2 font-mono">
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
2
2
|
import { HTTPSnippet } from "@zudoku/httpsnippet";
|
|
3
|
-
import {
|
|
3
|
+
import { useMemo, useState, useTransition } from "react";
|
|
4
4
|
import { useSearchParams } from "react-router";
|
|
5
5
|
import { useSelectedServerStore } from "../../authentication/state.js";
|
|
6
|
+
import { PathRenderer } from "../../components/PathRenderer.js";
|
|
6
7
|
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
7
8
|
import type { SchemaObject } from "../../oas/parser/index.js";
|
|
8
9
|
import { cn } from "../../util/cn.js";
|
|
@@ -114,31 +115,21 @@ export const Sidecar = ({
|
|
|
114
115
|
|
|
115
116
|
const requestBodyContent = operation.requestBody?.content;
|
|
116
117
|
|
|
117
|
-
const path =
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
{part}
|
|
133
|
-
</ColorizedParam>
|
|
134
|
-
) : (
|
|
135
|
-
part
|
|
136
|
-
)}
|
|
137
|
-
{i < arr.length - 1 ? "/" : null}
|
|
138
|
-
<wbr />
|
|
139
|
-
</Fragment>
|
|
140
|
-
);
|
|
141
|
-
});
|
|
118
|
+
const path = (
|
|
119
|
+
<PathRenderer
|
|
120
|
+
path={operation.path}
|
|
121
|
+
renderParam={({ name }) => (
|
|
122
|
+
<ColorizedParam
|
|
123
|
+
name={name}
|
|
124
|
+
backgroundOpacity="0"
|
|
125
|
+
// same as in `ParameterListItem`
|
|
126
|
+
slug={`${operation.slug}-${name}`}
|
|
127
|
+
>
|
|
128
|
+
{`{${name}}`}
|
|
129
|
+
</ColorizedParam>
|
|
130
|
+
)}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
142
133
|
|
|
143
134
|
const { selectedServer } = useSelectedServerStore();
|
|
144
135
|
|
|
@@ -3,6 +3,7 @@ import { InfoIcon } from "lucide-react";
|
|
|
3
3
|
import { Fragment, useEffect, useRef, useTransition } from "react";
|
|
4
4
|
import { FormProvider, useForm } from "react-hook-form";
|
|
5
5
|
import { Alert, AlertDescription, AlertTitle } from "zudoku/ui/Alert.js";
|
|
6
|
+
import { PathRenderer } from "../../../components/PathRenderer.js";
|
|
6
7
|
|
|
7
8
|
import { Label } from "zudoku/ui/Label.js";
|
|
8
9
|
import { RadioGroup, RadioGroupItem } from "zudoku/ui/RadioGroup.js";
|
|
@@ -222,36 +223,27 @@ export const Playground = ({
|
|
|
222
223
|
},
|
|
223
224
|
});
|
|
224
225
|
|
|
225
|
-
const path =
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
const path = (
|
|
227
|
+
<PathRenderer
|
|
228
|
+
path={url}
|
|
229
|
+
renderParam={({ name, originalValue, index }) => {
|
|
230
|
+
const formValue = formState.pathParams.find(
|
|
231
|
+
(param) => param.name === name,
|
|
232
|
+
)?.value;
|
|
230
233
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
return (
|
|
247
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
248
|
-
<Fragment key={part + i}>
|
|
249
|
-
{isPathParam ? pathParamValue : part}
|
|
250
|
-
{i < arr.length - 1 && "/"}
|
|
251
|
-
<wbr />
|
|
252
|
-
</Fragment>
|
|
253
|
-
);
|
|
254
|
-
});
|
|
234
|
+
return (
|
|
235
|
+
<ColorizedParam
|
|
236
|
+
name={name}
|
|
237
|
+
backgroundOpacity="0"
|
|
238
|
+
slug={name}
|
|
239
|
+
onClick={() => form.setFocus(`pathParams.${index}.value`)}
|
|
240
|
+
>
|
|
241
|
+
{formValue || originalValue}
|
|
242
|
+
</ColorizedParam>
|
|
243
|
+
);
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
);
|
|
255
247
|
|
|
256
248
|
const urlQueryParams = formState.queryParams
|
|
257
249
|
.filter((p) => p.active)
|
|
@@ -268,9 +260,7 @@ export const Playground = ({
|
|
|
268
260
|
{servers && servers.length > 1 ? (
|
|
269
261
|
<Select
|
|
270
262
|
onValueChange={(value) => {
|
|
271
|
-
startTransition(() =>
|
|
272
|
-
setSelectedServer(value);
|
|
273
|
-
});
|
|
263
|
+
startTransition(() => setSelectedServer(value));
|
|
274
264
|
}}
|
|
275
265
|
value={selectedServer}
|
|
276
266
|
defaultValue={selectedServer}
|
|
@@ -307,7 +297,7 @@ export const Playground = ({
|
|
|
307
297
|
<div className="border-r p-2 bg-muted rounded-l-md self-stretch font-semibold font-mono flex items-center">
|
|
308
298
|
{method.toUpperCase()}
|
|
309
299
|
</div>
|
|
310
|
-
<div className="
|
|
300
|
+
<div className="items-center p-2 font-mono text-xs break-words">
|
|
311
301
|
{serverSelect}
|
|
312
302
|
{path}
|
|
313
303
|
{urlQueryParams.length > 0 ? "?" : ""}
|
|
@@ -3,7 +3,6 @@ import { ListPlusIcon, RefreshCcwDotIcon } from "lucide-react";
|
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
4
|
import { Badge } from "zudoku/ui/Badge.js";
|
|
5
5
|
import { Markdown, ProseClasses } from "../../../components/Markdown.js";
|
|
6
|
-
import { CIRCULAR_REF } from "../../../oas/graphql/circular.js";
|
|
7
6
|
import type { SchemaObject } from "../../../oas/parser/index.js";
|
|
8
7
|
import { Button } from "../../../ui/Button.js";
|
|
9
8
|
import { cn } from "../../../util/cn.js";
|
|
@@ -12,6 +11,7 @@ import { LogicalGroup } from "./LogicalGroup/LogicalGroup.js";
|
|
|
12
11
|
import { SchemaView } from "./SchemaView.js";
|
|
13
12
|
import {
|
|
14
13
|
hasLogicalGroupings,
|
|
14
|
+
isCircularRef,
|
|
15
15
|
isComplexType,
|
|
16
16
|
LogicalSchemaTypeMap,
|
|
17
17
|
} from "./utils.js";
|
|
@@ -41,13 +41,10 @@ export const SchemaLogicalGroup = ({
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
const isCircularRef = (schema: unknown): schema is string =>
|
|
45
|
-
schema === CIRCULAR_REF;
|
|
46
|
-
|
|
47
44
|
const RecursiveIndicator = () => (
|
|
48
45
|
<div className="flex items-center gap-2 italic text-sm text-muted-foreground font-mono bg-muted px-2 py-0.5 rounded-md">
|
|
49
46
|
<RefreshCcwDotIcon size={16} />
|
|
50
|
-
<span>
|
|
47
|
+
<span>circular</span>
|
|
51
48
|
</div>
|
|
52
49
|
);
|
|
53
50
|
|
|
@@ -74,6 +71,8 @@ export const SchemaPropertyItem = ({
|
|
|
74
71
|
<div className="flex flex-col gap-1 justify-between text-sm">
|
|
75
72
|
<div className="flex gap-2 items-center">
|
|
76
73
|
<code>{name}</code>
|
|
74
|
+
<Badge variant="muted">object</Badge>
|
|
75
|
+
{group === "optional" && <Badge variant="outline">optional</Badge>}
|
|
77
76
|
<RecursiveIndicator />
|
|
78
77
|
</div>
|
|
79
78
|
</div>
|
|
@@ -96,6 +95,9 @@ export const SchemaPropertyItem = ({
|
|
|
96
95
|
)}
|
|
97
96
|
</Badge>
|
|
98
97
|
{group === "optional" && <Badge variant="outline">optional</Badge>}
|
|
98
|
+
{schema.type === "array" &&
|
|
99
|
+
"items" in schema &&
|
|
100
|
+
isCircularRef(schema.items) && <RecursiveIndicator />}
|
|
99
101
|
</div>
|
|
100
102
|
|
|
101
103
|
{schema.description && (
|
|
@@ -133,7 +135,9 @@ export const SchemaPropertyItem = ({
|
|
|
133
135
|
<SchemaView schema={schema} level={level + 1} />
|
|
134
136
|
) : (
|
|
135
137
|
schema.type === "array" &&
|
|
136
|
-
|
|
138
|
+
"items" in schema &&
|
|
139
|
+
typeof schema.items === "object" &&
|
|
140
|
+
!isCircularRef(schema.items) && (
|
|
137
141
|
<SchemaView schema={schema.items} level={level + 1} />
|
|
138
142
|
)
|
|
139
143
|
)}
|
|
@@ -3,7 +3,10 @@ import type { SchemaObject } from "../../../oas/parser/index.js";
|
|
|
3
3
|
import { Card, CardContent, CardHeader, CardTitle } from "../../../ui/Card.js";
|
|
4
4
|
import { cn } from "../../../util/cn.js";
|
|
5
5
|
import { groupBy } from "../../../util/groupBy.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
SchemaLogicalGroup,
|
|
8
|
+
SchemaPropertyItem,
|
|
9
|
+
} from "./SchemaPropertyItem.js";
|
|
7
10
|
import { hasLogicalGroupings } from "./utils.js";
|
|
8
11
|
|
|
9
12
|
export const SchemaView = ({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CIRCULAR_REF } from "../../../oas/graphql/circular.js";
|
|
1
2
|
import type { SchemaObject } from "../../../oas/parser/index.js";
|
|
2
3
|
|
|
3
4
|
export const isComplexType = (value: SchemaObject) =>
|
|
@@ -16,3 +17,6 @@ export const LogicalSchemaTypeMap = {
|
|
|
16
17
|
} as const;
|
|
17
18
|
|
|
18
19
|
export type LogicalGroupType = "AND" | "OR" | "ONE";
|
|
20
|
+
|
|
21
|
+
export const isCircularRef = (schema: unknown): schema is string =>
|
|
22
|
+
schema === CIRCULAR_REF;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaComponents.js","sourceRoot":"","sources":["../../../../../src/lib/plugins/openapi/schema/SchemaComponents.tsx"],"names":[],"mappings":"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"}
|