zudoku 0.28.0 → 0.28.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/app/main.js +1 -3
- 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 +5 -0
- package/dist/lib/components/index.js +6 -2
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/components/navigation/Sidebar.js +6 -1
- package/dist/lib/components/navigation/Sidebar.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/oas/graphql/index.js +11 -10
- package/dist/lib/oas/graphql/index.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.d.ts +2 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +2 -2
- 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/PlaygroundDialogWrapper.js +6 -2
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.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/Headers.d.ts +2 -3
- package/dist/lib/plugins/openapi/playground/Headers.js +2 -2
- package/dist/lib/plugins/openapi/playground/Headers.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.d.ts +3 -0
- package/dist/lib/plugins/openapi/playground/Playground.js +8 -16
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.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/lib/util/scrollIntoViewIfNeeded.d.ts +1 -0
- package/dist/lib/util/scrollIntoViewIfNeeded.js +14 -0
- package/dist/lib/util/scrollIntoViewIfNeeded.js.map +1 -0
- package/dist/lib/util/useScrollToAnchor.js +1 -13
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/plugin-api.js +97 -95
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-theme-css.js +7 -4
- package/dist/vite/plugin-theme-css.js.map +1 -1
- package/dist/vite/prerender.js +0 -1
- package/dist/vite/prerender.js.map +1 -1
- package/lib/{AuthenticationPlugin-Du8cLBSr.js → AuthenticationPlugin-DeEA69mE.js} +3 -3
- package/lib/{AuthenticationPlugin-Du8cLBSr.js.map → AuthenticationPlugin-DeEA69mE.js.map} +1 -1
- package/lib/{Markdown-Cyrx_JrO.js → Markdown-LcMEZ0Sn.js} +2 -2
- package/lib/{Markdown-Cyrx_JrO.js.map → Markdown-LcMEZ0Sn.js.map} +1 -1
- package/lib/{MdxPage-DewragjB.js → MdxPage-DkH3V4hV.js} +5 -5
- package/lib/{MdxPage-DewragjB.js.map → MdxPage-DkH3V4hV.js.map} +1 -1
- package/lib/{OpenApiRoute-UrC_t0e5.js → OpenApiRoute-ULLXjfro.js} +3 -3
- package/lib/{OpenApiRoute-UrC_t0e5.js.map → OpenApiRoute-ULLXjfro.js.map} +1 -1
- package/lib/{OperationList-D_ejrepA.js → OperationList-wzZNceUl.js} +738 -727
- package/lib/OperationList-wzZNceUl.js.map +1 -0
- package/lib/{Select-CnCZ4WhS.js → Select-DJkXPPD0.js} +3 -3
- package/lib/{Select-CnCZ4WhS.js.map → Select-DJkXPPD0.js.map} +1 -1
- package/lib/{SlotletProvider-mQiPDQIH.js → SlotletProvider-D1t2ePCI.js} +4 -4
- package/lib/{SlotletProvider-mQiPDQIH.js.map → SlotletProvider-D1t2ePCI.js.map} +1 -1
- package/lib/{ZudokuContext-BTUJPpQl.js → ZudokuContext-dUyBGMap.js} +2 -2
- package/lib/{ZudokuContext-BTUJPpQl.js.map → ZudokuContext-dUyBGMap.js.map} +1 -1
- package/lib/{chunk-SYFQ2XB5-BPvC-soB.js → chunk-SYFQ2XB5-QijJrSf0.js} +3 -3
- package/lib/{chunk-SYFQ2XB5-BPvC-soB.js.map → chunk-SYFQ2XB5-QijJrSf0.js.map} +1 -1
- 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-DIztAu7i.js} +12 -9
- package/lib/{createServer-BydbkTsd.js.map → createServer-DIztAu7i.js.map} +1 -1
- package/lib/{hook-FT3SJLe_.js → hook-CiX69UZ6.js} +2 -2
- package/lib/{hook-FT3SJLe_.js.map → hook-CiX69UZ6.js.map} +1 -1
- package/lib/{index-DGugJOLc.js → index-DrR58fsJ.js} +663 -629
- package/lib/index-DrR58fsJ.js.map +1 -0
- package/lib/{useExposedProps-BLKFBylA.js → useExposedProps-Bbf99zic.js} +2 -2
- package/lib/{useExposedProps-BLKFBylA.js.map → useExposedProps-Bbf99zic.js.map} +1 -1
- package/lib/{useScrollToAnchor-eRM9tVvD.js → useScrollToAnchor-DYGn1MT9.js} +86 -90
- package/lib/useScrollToAnchor-DYGn1MT9.js.map +1 -0
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +3 -3
- package/lib/zudoku.components.js +596 -492
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-api-catalog.js +3 -3
- package/lib/zudoku.plugin-api-keys.js +5 -5
- package/lib/zudoku.plugin-custom-pages.js +2 -2
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +3 -3
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/package.json +2 -2
- package/src/app/main.tsx +7 -3
- package/src/lib/components/PathRenderer.tsx +59 -0
- package/src/lib/components/ThemeSwitch.tsx +15 -14
- package/src/lib/components/index.ts +9 -5
- package/src/lib/components/navigation/Sidebar.tsx +7 -1
- package/src/lib/components/navigation/SidebarCategory.tsx +43 -41
- package/src/lib/oas/graphql/circular.ts +27 -6
- package/src/lib/oas/graphql/index.ts +14 -17
- package/src/lib/plugins/openapi/ColorizedParam.tsx +3 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +7 -2
- package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -1
- package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +7 -2
- package/src/lib/plugins/openapi/Sidecar.tsx +17 -26
- package/src/lib/plugins/openapi/playground/Headers.tsx +5 -9
- package/src/lib/plugins/openapi/playground/PathParams.tsx +1 -1
- package/src/lib/plugins/openapi/playground/Playground.tsx +27 -34
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +5 -2
- 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/src/lib/util/scrollIntoViewIfNeeded.ts +18 -0
- package/src/lib/util/useScrollToAnchor.ts +1 -19
- 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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import { s as j } from "./index-CjJS0l4l.js";
|
|
3
|
-
import { u as b } from "./ZudokuContext-
|
|
4
|
-
import { b as y } from "./chunk-SYFQ2XB5-
|
|
3
|
+
import { u as b } from "./ZudokuContext-dUyBGMap.js";
|
|
4
|
+
import { b as y } from "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
5
5
|
import { Head as v, Link as N } from "./zudoku.components.js";
|
|
6
6
|
import { u as w } from "./state-mM7uaXTW.js";
|
|
7
|
-
import { M as C } from "./Markdown-
|
|
7
|
+
import { M as C } from "./Markdown-LcMEZ0Sn.js";
|
|
8
8
|
import { c as h } from "./cn-qaFjX9_3.js";
|
|
9
9
|
const f = (r, n) => j(`${r}-${n}`), k = ({
|
|
10
10
|
items: r,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import { RotateCwIcon as g, TrashIcon as f, EyeOffIcon as j, EyeIcon as v, CheckIcon as w, CopyIcon as b, FileKey2Icon as K } from "lucide-react";
|
|
3
|
-
import { D as k, S as m, R as N } from "./SlotletProvider-
|
|
3
|
+
import { D as k, S as m, R as N } from "./SlotletProvider-D1t2ePCI.js";
|
|
4
4
|
import { i as c } from "./invariant-Caa8-XvF.js";
|
|
5
|
-
import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-
|
|
5
|
+
import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-DJkXPPD0.js";
|
|
6
6
|
import { a as P } from "./index.esm-CrSoEshU.js";
|
|
7
|
-
import { a as D, L as u, O as R } from "./chunk-SYFQ2XB5-
|
|
8
|
-
import { a as y, e as q, u as O } from "./ZudokuContext-
|
|
7
|
+
import { a as D, L as u, O as R } from "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
8
|
+
import { a as y, e as q, u as O } from "./ZudokuContext-dUyBGMap.js";
|
|
9
9
|
import { Button as l } from "./ui/Button.js";
|
|
10
10
|
import { Input as z } from "./ui/Input.js";
|
|
11
|
-
import { u as F } from "./hook-
|
|
11
|
+
import { u as F } from "./hook-CiX69UZ6.js";
|
|
12
12
|
import { useState as p } from "react";
|
|
13
13
|
import { c as T } from "./cn-qaFjX9_3.js";
|
|
14
14
|
const L = ({ service: t }) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { j as o } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import a from "react";
|
|
3
|
-
import { P as n } from "./Markdown-
|
|
3
|
+
import { P as n } from "./Markdown-LcMEZ0Sn.js";
|
|
4
4
|
import { c } from "./cn-qaFjX9_3.js";
|
|
5
|
-
import { u as p } from "./useExposedProps-
|
|
5
|
+
import { u as p } from "./useExposedProps-Bbf99zic.js";
|
|
6
6
|
const u = ({
|
|
7
7
|
element: t,
|
|
8
8
|
render: s,
|
|
@@ -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-DkH3V4hV.js"), { default: p, ...g } = await a();
|
|
78
78
|
return {
|
|
79
79
|
element: /* @__PURE__ */ P.jsx(
|
|
80
80
|
l,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import "./index-CjJS0l4l.js";
|
|
3
3
|
import "lucide-react";
|
|
4
|
-
import "./chunk-SYFQ2XB5-
|
|
5
|
-
import "./hook-
|
|
4
|
+
import "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
5
|
+
import "./hook-CiX69UZ6.js";
|
|
6
6
|
import "./ui/Button.js";
|
|
7
7
|
import "./joinUrl-nLx9pD-Z.js";
|
|
8
|
-
import { o as f } from "./index-
|
|
8
|
+
import { o as f } from "./index-DrR58fsJ.js";
|
|
9
9
|
export {
|
|
10
10
|
f as openApiPlugin
|
|
11
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://zudoku.dev",
|
|
6
6
|
"repository": {
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
"react-dom": ">=19"
|
|
246
246
|
},
|
|
247
247
|
"optionalDependencies": {
|
|
248
|
-
"@clerk/clerk-js": "^5.
|
|
248
|
+
"@clerk/clerk-js": "^5.51.0",
|
|
249
249
|
"@sentry/react": "^8.50.0"
|
|
250
250
|
},
|
|
251
251
|
"scripts": {
|
package/src/app/main.tsx
CHANGED
|
@@ -11,12 +11,16 @@ 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 {
|
|
14
|
+
import {
|
|
15
|
+
Layout,
|
|
16
|
+
RouteGuard,
|
|
17
|
+
RouterError,
|
|
18
|
+
StatusPage,
|
|
19
|
+
Zudoku,
|
|
20
|
+
} from "zudoku/components";
|
|
15
21
|
import type { ZudokuConfig } from "../config/config.js";
|
|
16
|
-
import { StatusPage } from "../lib/components/StatusPage.js";
|
|
17
22
|
import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
|
|
18
23
|
import { isNavigationPlugin } from "../lib/core/plugins.js";
|
|
19
|
-
import { RouteGuard } from "../lib/core/RouteGuard.js";
|
|
20
24
|
|
|
21
25
|
export const convertZudokuConfigToOptions = (
|
|
22
26
|
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,17 @@ 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 { StatusPage as StatusPageImport } from "./StatusPage.js";
|
|
24
|
+
import { Zudoku as ZudokuImport } from "./Zudoku.js";
|
|
23
25
|
|
|
24
26
|
export const useMDXComponents = /*@__PURE__*/ useMDXComponentsImport;
|
|
25
27
|
export const Layout = /*@__PURE__*/ LayoutImport;
|
|
@@ -27,6 +29,7 @@ export const RouterError = /*@__PURE__*/ RouterErrorImport;
|
|
|
27
29
|
export const ServerError = /*@__PURE__*/ ServerErrorImport;
|
|
28
30
|
export const Bootstrap = /*@__PURE__*/ BootstrapImport;
|
|
29
31
|
export const BootstrapStatic = /*@__PURE__*/ BootstrapStaticImport;
|
|
32
|
+
export const RouteGuard = /*@__PURE__*/ RouteGuardImport;
|
|
30
33
|
|
|
31
34
|
export const Head = /*@__PURE__*/ Helmet;
|
|
32
35
|
|
|
@@ -36,6 +39,7 @@ export const useCache = /*@__PURE__*/ useCacheImport;
|
|
|
36
39
|
export const CACHE_KEYS = /*@__PURE__*/ CACHE_KEYS_IMPORT;
|
|
37
40
|
export const Zudoku = /*@__PURE__*/ ZudokuImport;
|
|
38
41
|
|
|
42
|
+
export const StatusPage = /*@__PURE__*/ StatusPageImport;
|
|
39
43
|
export const Callout = /*@__PURE__*/ CalloutImport;
|
|
40
44
|
export const Markdown = /*@__PURE__*/ MarkdownImport;
|
|
41
45
|
export const Spinner = /*@__PURE__*/ SpinnerImport;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useRef } from "react";
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
4
4
|
import { DrawerContent, DrawerTitle } from "../../ui/Drawer.js";
|
|
5
|
+
import { scrollIntoViewIfNeeded } from "../../util/scrollIntoViewIfNeeded.js";
|
|
5
6
|
import { useCurrentNavigation } from "../context/ZudokuContext.js";
|
|
6
7
|
import { Slotlet } from "../SlotletProvider.js";
|
|
7
8
|
import { SidebarItem } from "./SidebarItem.js";
|
|
@@ -15,6 +16,11 @@ export const Sidebar = ({
|
|
|
15
16
|
const navRef = useRef<HTMLDivElement | null>(null);
|
|
16
17
|
const navigation = useCurrentNavigation();
|
|
17
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const active = navRef.current?.querySelector('[aria-current="page"]');
|
|
21
|
+
scrollIntoViewIfNeeded(active ?? null);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
18
24
|
return (
|
|
19
25
|
<>
|
|
20
26
|
<SidebarWrapper
|
|
@@ -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",
|
|
@@ -87,27 +87,24 @@ const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
|
|
|
87
87
|
const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
|
|
88
88
|
|
|
89
89
|
export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
.flatMap((operation) =>
|
|
96
|
-
typeof operation === "object" && "tags" in operation
|
|
97
|
-
? (operation.tags ?? [])
|
|
98
|
-
: [],
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// Remove duplicates and tags that appear in the schema
|
|
102
|
-
const uniqueOperationTags = [...new Set(operationTags)].filter(
|
|
103
|
-
(tag) => !tags.some((rootTag) => rootTag.name === tag),
|
|
90
|
+
const rootTags = schema.tags ?? [];
|
|
91
|
+
const operationTags = new Set(
|
|
92
|
+
Object.values(schema.paths ?? {})
|
|
93
|
+
.flatMap((path) => Object.values(path ?? {}))
|
|
94
|
+
.flatMap((op) => (op as OperationObject).tags ?? []),
|
|
104
95
|
);
|
|
105
|
-
|
|
96
|
+
|
|
97
|
+
return [
|
|
98
|
+
// Keep root tags that are actually used in operations
|
|
99
|
+
...rootTags.filter((tag) => operationTags.has(tag.name)),
|
|
100
|
+
// Add tags found in operations but not defined in root tags
|
|
101
|
+
...[...operationTags]
|
|
102
|
+
.filter((tag) => !rootTags.some((rt) => rt.name === tag))
|
|
103
|
+
.map((tag) => ({ name: tag })),
|
|
104
|
+
];
|
|
106
105
|
};
|
|
107
106
|
|
|
108
107
|
const getAllOperations = (paths?: PathsObject) => {
|
|
109
|
-
const start = performance.now();
|
|
110
|
-
|
|
111
108
|
const operations = Object.entries(paths ?? {}).flatMap(([path, value]) =>
|
|
112
109
|
HttpMethods.flatMap((method) => {
|
|
113
110
|
if (!value?.[method]) return [];
|
|
@@ -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}
|
|
@@ -11,7 +11,7 @@ import { FragmentType, useFragment } from "./graphql/index.js";
|
|
|
11
11
|
import { SchemaView } from "./schema/SchemaView.js";
|
|
12
12
|
import { methodForColor } from "./util/methodToColor.js";
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
|
|
15
15
|
export type ParameterGroup = (typeof PARAM_GROUPS)[number];
|
|
16
16
|
|
|
17
17
|
export const OperationListItem = ({
|
|
@@ -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">
|
|
@@ -15,10 +15,15 @@ export const PlaygroundDialogWrapper = ({
|
|
|
15
15
|
}) => {
|
|
16
16
|
const headers = operation.parameters
|
|
17
17
|
?.filter((p) => p.in === "header")
|
|
18
|
+
.sort((a, b) => (a.required && !b.required ? -1 : 1))
|
|
18
19
|
.map((p) => ({
|
|
19
20
|
name: p.name,
|
|
20
|
-
defaultValue:
|
|
21
|
-
|
|
21
|
+
defaultValue:
|
|
22
|
+
p.schema?.default ?? p.examples?.find((x) => x.value)?.value ?? "",
|
|
23
|
+
defaultActive: p.required ?? false,
|
|
24
|
+
isRequired: p.required ?? false,
|
|
25
|
+
enum: p.schema?.type == "array" ? p.schema?.items?.enum : p.schema?.enum,
|
|
26
|
+
type: p.schema?.type ?? "string",
|
|
22
27
|
}));
|
|
23
28
|
const queryParams = operation.parameters
|
|
24
29
|
?.filter((p) => p.in === "query")
|
|
@@ -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
|
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
Controller,
|
|
6
6
|
useFieldArray,
|
|
7
7
|
useFormContext,
|
|
8
|
-
UseFormRegister,
|
|
9
8
|
} from "react-hook-form";
|
|
10
9
|
import { Card } from "zudoku/ui/Card.js";
|
|
11
10
|
import { Checkbox } from "zudoku/ui/Checkbox.js";
|
|
@@ -44,13 +43,7 @@ const headerOptions = Object.freeze([
|
|
|
44
43
|
"X-Requested-With",
|
|
45
44
|
]);
|
|
46
45
|
|
|
47
|
-
export const Headers = ({
|
|
48
|
-
control,
|
|
49
|
-
register,
|
|
50
|
-
}: {
|
|
51
|
-
register: UseFormRegister<PlaygroundForm>;
|
|
52
|
-
control: Control<PlaygroundForm>;
|
|
53
|
-
}) => {
|
|
46
|
+
export const Headers = ({ control }: { control: Control<PlaygroundForm> }) => {
|
|
54
47
|
const { fields, append, remove } = useFieldArray<PlaygroundForm>({
|
|
55
48
|
control,
|
|
56
49
|
name: "headers",
|
|
@@ -81,7 +74,10 @@ export const Headers = ({
|
|
|
81
74
|
<Card className="overflow-hidden">
|
|
82
75
|
<ParamsGrid>
|
|
83
76
|
{fields.map((header, i) => (
|
|
84
|
-
<div
|
|
77
|
+
<div
|
|
78
|
+
key={header.name}
|
|
79
|
+
className="group grid col-span-full grid-cols-subgrid"
|
|
80
|
+
>
|
|
85
81
|
<div className="flex items-center gap-2 ">
|
|
86
82
|
<Controller
|
|
87
83
|
control={control}
|