zudoku 0.3.0-dev.10 → 0.3.0-dev.12
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/App.js +8 -6
- package/dist/app/App.js.map +1 -1
- package/dist/config/config.d.ts +5 -14
- package/dist/lib/authentication/authentication.d.ts +2 -2
- package/dist/lib/components/DevPortal.d.ts +2 -20
- package/dist/lib/components/DevPortal.js +13 -8
- package/dist/lib/components/DevPortal.js.map +1 -1
- package/dist/lib/components/Header.js +2 -2
- package/dist/lib/components/Header.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +9 -4
- package/dist/lib/components/Heading.js +17 -2
- package/dist/lib/components/Heading.js.map +1 -1
- package/dist/lib/components/Layout.js +1 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/context/DevPortalProvider.d.ts +1 -1
- package/dist/lib/components/context/DevPortalProvider.js +2 -2
- package/dist/lib/components/context/DevPortalProvider.js.map +1 -1
- package/dist/lib/core/DevPortalContext.d.ts +33 -3
- package/dist/lib/core/DevPortalContext.js +4 -2
- package/dist/lib/core/DevPortalContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +7 -4
- package/dist/lib/core/plugins.js +1 -0
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/oas/graphql/index.js +1 -1
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/oas/parser/index.js +3 -1
- package/dist/lib/oas/parser/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.d.ts +3 -2
- package/dist/lib/plugins/markdown/MdxPage.js +5 -4
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/markdown/generateRoutes.d.ts +2 -2
- package/dist/lib/plugins/markdown/generateRoutes.js +2 -2
- package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
- package/dist/lib/plugins/markdown/index.d.ts +4 -1
- package/dist/lib/plugins/markdown/index.js +2 -2
- package/dist/lib/plugins/markdown/index.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +4 -3
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +8 -4
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterList.js +1 -1
- package/dist/lib/plugins/openapi/ParameterList.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/{MakeRequest.d.ts → PlaygroundDialogWrapper.d.ts} +1 -1
- package/dist/lib/plugins/openapi/{MakeRequest.js → PlaygroundDialogWrapper.js} +4 -4
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -0
- package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +1 -9
- package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
- package/dist/lib/plugins/openapi/ResponsesSidecarBox.js +1 -1
- package/dist/lib/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
- package/dist/lib/plugins/openapi/SchemaListView.js +4 -26
- package/dist/lib/plugins/openapi/SchemaListView.js.map +1 -1
- package/dist/lib/plugins/openapi/SchemaListViewItem.d.ts +7 -0
- package/dist/lib/plugins/openapi/SchemaListViewItem.js +16 -0
- package/dist/lib/plugins/openapi/SchemaListViewItem.js.map +1 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.d.ts +8 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js +17 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js.map +1 -0
- package/dist/lib/plugins/openapi/Sidecar.js +2 -2
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +8 -0
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +4 -4
- package/dist/lib/plugins/openapi/playground/Playground.js +7 -11
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.d.ts +3 -0
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +10 -0
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -0
- package/dist/lib/plugins/openapi/util/prose.d.ts +1 -0
- package/dist/lib/plugins/openapi/util/prose.js +4 -0
- package/dist/lib/plugins/openapi/util/prose.js.map +1 -0
- package/dist/lib/plugins/openapi/worker/worker.js +25 -1
- package/dist/lib/plugins/openapi/worker/worker.js.map +1 -1
- package/dist/lib/ui/button-variants.d.ts +1 -1
- package/dist/lib/util/MdxComponents.js +1 -1
- package/dist/lib/util/MdxComponents.js.map +1 -1
- package/dist/lib/util/objectEntries.d.ts +4 -0
- package/dist/lib/util/objectEntries.js +2 -0
- package/dist/lib/util/objectEntries.js.map +1 -0
- package/dist/lib/util/renderIf.d.ts +1 -0
- package/dist/lib/util/renderIf.js +2 -0
- package/dist/lib/util/renderIf.js.map +1 -0
- package/dist/vite/plugin-docs.js +1 -1
- package/dist/vite/plugin-docs.js.map +1 -1
- package/lib/{Spinner-DCwVN24H.js → Spinner-CbtkR-Im.js} +3249 -3232
- package/lib/assets/{worker-BCcpCNJ7.js → worker-DGvzLstc.js} +9843 -9800
- package/lib/zudoku.components.js +174 -161
- package/lib/zudoku.openapi-worker.js +12 -12
- package/lib/zudoku.plugins.js +3722 -3712
- package/package.json +2 -1
- package/src/app/App.tsx +9 -7
- package/src/lib/authentication/authentication.ts +2 -5
- package/src/lib/components/DevPortal.tsx +12 -27
- package/src/lib/components/Header.tsx +4 -4
- package/src/lib/components/Heading.tsx +26 -7
- package/src/lib/components/Layout.tsx +1 -1
- package/src/lib/components/context/DevPortalProvider.ts +2 -2
- package/src/lib/core/DevPortalContext.ts +38 -10
- package/src/lib/core/plugins.ts +10 -5
- package/src/lib/oas/graphql/index.ts +2 -2
- package/src/lib/oas/parser/index.ts +3 -1
- package/src/lib/plugins/markdown/MdxPage.tsx +49 -32
- package/src/lib/plugins/markdown/generateRoutes.tsx +12 -2
- package/src/lib/plugins/markdown/index.tsx +8 -1
- package/src/lib/plugins/openapi/OperationList.tsx +9 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +39 -18
- package/src/lib/plugins/openapi/ParameterList.tsx +1 -1
- package/src/lib/plugins/openapi/ParameterListItem.tsx +3 -4
- package/src/lib/plugins/openapi/{MakeRequest.tsx → PlaygroundDialogWrapper.tsx} +3 -3
- package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -17
- package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +3 -1
- package/src/lib/plugins/openapi/SchemaListView.tsx +15 -182
- package/src/lib/plugins/openapi/SchemaListViewItem.tsx +110 -0
- package/src/lib/plugins/openapi/SchemaListViewItemGroup.tsx +63 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +2 -2
- package/src/lib/plugins/openapi/index.tsx +17 -4
- package/src/lib/plugins/openapi/playground/Playground.tsx +157 -187
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +34 -0
- package/src/lib/plugins/openapi/util/prose.ts +7 -0
- package/src/lib/plugins/openapi/worker/worker.ts +27 -1
- package/src/lib/util/MdxComponents.tsx +1 -1
- package/src/lib/util/objectEntries.ts +5 -0
- package/src/lib/util/renderIf.ts +4 -0
- package/dist/lib/plugins/openapi/MakeRequest.js.map +0 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Heading } from "../../components/Heading.js";
|
|
2
|
-
import { Markdown
|
|
2
|
+
import { Markdown } from "../../components/Markdown.js";
|
|
3
3
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/Tabs.js";
|
|
4
|
+
import { renderIf } from "../../util/renderIf.js";
|
|
4
5
|
import { OperationsFragment } from "./OperationList.js";
|
|
5
6
|
import { ParameterList } from "./ParameterList.js";
|
|
6
7
|
import { SchemaListView } from "./SchemaListView.js";
|
|
7
8
|
import { Sidecar } from "./Sidecar.js";
|
|
8
9
|
import { FragmentType, useFragment } from "./graphql/index.js";
|
|
10
|
+
import { SchemaProseClasses } from "./util/prose.js";
|
|
9
11
|
|
|
10
12
|
export const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
|
|
11
13
|
export type ParameterGroup = (typeof PARAM_GROUPS)[number];
|
|
@@ -20,24 +22,24 @@ export const OperationListItem = ({
|
|
|
20
22
|
operation.parameters ?? [],
|
|
21
23
|
(param) => param.in,
|
|
22
24
|
);
|
|
23
|
-
const first = operation.responses.
|
|
25
|
+
const first = operation.responses.at(0);
|
|
24
26
|
return (
|
|
25
27
|
<div
|
|
26
28
|
key={operation.operationId}
|
|
27
|
-
className="grid grid-cols-
|
|
29
|
+
className="grid grid-cols-[4fr_3fr] gap-8 items-start border-b-2 mb-16 pb-16 border-border"
|
|
28
30
|
>
|
|
29
|
-
<div className=
|
|
30
|
-
<Heading
|
|
31
|
-
level={2}
|
|
32
|
-
className="mt-0"
|
|
33
|
-
id={operation.slug}
|
|
34
|
-
registerSidebarAnchor
|
|
35
|
-
>
|
|
31
|
+
<div className="flex flex-col gap-4">
|
|
32
|
+
<Heading level={2} id={operation.slug} registerSidebarAnchor>
|
|
36
33
|
{operation.summary}
|
|
37
34
|
</Heading>
|
|
38
|
-
{operation.description &&
|
|
35
|
+
{operation.description && (
|
|
36
|
+
<Markdown
|
|
37
|
+
className={SchemaProseClasses}
|
|
38
|
+
content={operation.description}
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
39
41
|
{operation.parameters && operation.parameters.length > 0 && (
|
|
40
|
-
|
|
42
|
+
<>
|
|
41
43
|
{PARAM_GROUPS.flatMap((group) =>
|
|
42
44
|
groupedParameters[group]?.length ? (
|
|
43
45
|
<ParameterList
|
|
@@ -50,11 +52,22 @@ export const OperationListItem = ({
|
|
|
50
52
|
[]
|
|
51
53
|
),
|
|
52
54
|
)}
|
|
53
|
-
|
|
55
|
+
</>
|
|
54
56
|
)}
|
|
57
|
+
{renderIf(operation.requestBody?.content?.at(0)?.schema, (schema) => (
|
|
58
|
+
<div className="mt-4 flex flex-col gap-4">
|
|
59
|
+
<Heading level={3} className="capitalize">
|
|
60
|
+
Request Body
|
|
61
|
+
</Heading>
|
|
62
|
+
<SchemaListView schema={schema} />
|
|
63
|
+
</div>
|
|
64
|
+
))}
|
|
55
65
|
{operation.responses.length > 0 && (
|
|
56
66
|
<>
|
|
57
|
-
<Heading
|
|
67
|
+
<Heading
|
|
68
|
+
level={3}
|
|
69
|
+
className="capitalize mt-8 pt-8 border-border border-t"
|
|
70
|
+
>
|
|
58
71
|
Responses
|
|
59
72
|
</Heading>
|
|
60
73
|
<Tabs defaultValue={`${first?.statusCode}${first?.description}`}>
|
|
@@ -75,10 +88,18 @@ export const OperationListItem = ({
|
|
|
75
88
|
value={response.statusCode + response.description}
|
|
76
89
|
key={response.statusCode}
|
|
77
90
|
>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
{renderIf(
|
|
92
|
+
response.content?.find((content) => content.schema),
|
|
93
|
+
(content) => {
|
|
94
|
+
return (
|
|
95
|
+
<SchemaListView schema={content.schema} name="" />
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
) ?? (
|
|
99
|
+
<div className="border-border font-mono text-sm border rounded p-4">
|
|
100
|
+
No response body
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
82
103
|
</TabsContent>
|
|
83
104
|
))}
|
|
84
105
|
</ul>
|
|
@@ -18,7 +18,7 @@ export const ParameterList = ({
|
|
|
18
18
|
<Heading level={3} id={`${id}/${group}-parameters`} className="capitalize">
|
|
19
19
|
{group === "header" ? "Headers" : `${group} Parameters`}
|
|
20
20
|
</Heading>
|
|
21
|
-
<ul className="list-none m-0 px-0 overflow-hidden">
|
|
21
|
+
<ul className="list-none m-0 px-0 overflow-hidden border border-border divide-y divide-border rounded">
|
|
22
22
|
{parameters.map((parameter) => (
|
|
23
23
|
<ParameterListItem
|
|
24
24
|
key={`${parameter.name}-${parameter.in}`}
|
|
@@ -28,14 +28,13 @@ export const ParameterListItem = ({
|
|
|
28
28
|
group: ParameterGroup;
|
|
29
29
|
id: string;
|
|
30
30
|
}) => (
|
|
31
|
-
<li className="
|
|
31
|
+
<li className="p-4 bg-border/20 text-sm flex flex-col gap-1">
|
|
32
32
|
<div className="flex items-center gap-2">
|
|
33
33
|
<code>
|
|
34
34
|
{group === "path" ? (
|
|
35
35
|
<ColorizedParam
|
|
36
36
|
name={parameter.name}
|
|
37
37
|
backgroundOpacity="15%"
|
|
38
|
-
className="px-1"
|
|
39
38
|
slug={id + "-" + parameter.name.toLocaleLowerCase()}
|
|
40
39
|
/>
|
|
41
40
|
) : (
|
|
@@ -43,12 +42,12 @@ export const ParameterListItem = ({
|
|
|
43
42
|
)}
|
|
44
43
|
</code>
|
|
45
44
|
{parameter.required && (
|
|
46
|
-
<span className="py-px px-1.5 font-medium
|
|
45
|
+
<span className="py-px px-1.5 font-medium bg-primary/75 text-muted rounded-lg">
|
|
47
46
|
required
|
|
48
47
|
</span>
|
|
49
48
|
)}
|
|
50
49
|
{getParameterSchema(parameter).type && (
|
|
51
|
-
<span className="text-
|
|
50
|
+
<span className="text-muted-foreground">
|
|
52
51
|
{getParameterSchema(parameter).type}
|
|
53
52
|
</span>
|
|
54
53
|
)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { graphql } from "./graphql/index.js";
|
|
2
2
|
import { useOasConfig } from "./index.js";
|
|
3
3
|
import type { OperationListItemResult } from "./OperationList.js";
|
|
4
|
-
import {
|
|
4
|
+
import { PlaygroundDialog } from "./playground/PlaygroundDialog.js";
|
|
5
5
|
|
|
6
6
|
import { useQuery } from "urql";
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ const GetServerQuery = graphql(/* GraphQL */ `
|
|
|
13
13
|
}
|
|
14
14
|
`);
|
|
15
15
|
|
|
16
|
-
export const
|
|
16
|
+
export const PlaygroundDialogWrapper = ({
|
|
17
17
|
operation,
|
|
18
18
|
}: {
|
|
19
19
|
operation: OperationListItemResult;
|
|
@@ -50,7 +50,7 @@ export const MakeRequest = ({
|
|
|
50
50
|
false;
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<
|
|
53
|
+
<PlaygroundDialog
|
|
54
54
|
host={server.data?.schema.url ?? ""}
|
|
55
55
|
method={operation.method}
|
|
56
56
|
url={operation.path}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
1
|
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
3
2
|
import { type SchemaObject } from "../../oas/graphql/index.js";
|
|
4
3
|
import type { OperationListItemResult } from "./OperationList.js";
|
|
5
4
|
import * as SidecarBox from "./SidecarBox.js";
|
|
6
|
-
import { SimpleSelect } from "./SimpleSelect.js";
|
|
7
5
|
import { generateSchemaExample } from "./util/generateSchemaExample.js";
|
|
8
6
|
|
|
9
7
|
type Content = NonNullable<
|
|
@@ -12,24 +10,13 @@ type Content = NonNullable<
|
|
|
12
10
|
|
|
13
11
|
// @todo should we handle multiple content types?
|
|
14
12
|
export const RequestBodySidecarBox = ({ content }: { content: Content }) => {
|
|
15
|
-
const [selected, setSelected] = useState("example");
|
|
16
|
-
|
|
17
13
|
if (!content.length) return null;
|
|
18
14
|
|
|
19
15
|
return (
|
|
20
16
|
<>
|
|
21
|
-
<div>lol</div>
|
|
22
17
|
<SidecarBox.Root>
|
|
23
18
|
<SidecarBox.Head className="text-xs flex justify-between items-center">
|
|
24
|
-
<span className="font-mono">Request Body</span>
|
|
25
|
-
<SimpleSelect
|
|
26
|
-
value={selected}
|
|
27
|
-
onChange={(e) => setSelected(e.target.value)}
|
|
28
|
-
options={[
|
|
29
|
-
{ value: "example", label: "Example" },
|
|
30
|
-
{ value: "schema", label: "Schema" },
|
|
31
|
-
]}
|
|
32
|
-
/>
|
|
19
|
+
<span className="font-mono">Request Body Example</span>
|
|
33
20
|
</SidecarBox.Head>
|
|
34
21
|
<SidecarBox.Body>
|
|
35
22
|
<SyntaxHighlight
|
|
@@ -38,9 +25,7 @@ export const RequestBodySidecarBox = ({ content }: { content: Content }) => {
|
|
|
38
25
|
copyable
|
|
39
26
|
className="text-xs"
|
|
40
27
|
code={JSON.stringify(
|
|
41
|
-
|
|
42
|
-
? generateSchemaExample(content[0].schema as SchemaObject)
|
|
43
|
-
: content[0].schema,
|
|
28
|
+
generateSchemaExample(content[0].schema as SchemaObject),
|
|
44
29
|
null,
|
|
45
30
|
2,
|
|
46
31
|
)}
|
|
@@ -52,7 +52,9 @@ export const ResponsesSidecarBox = ({
|
|
|
52
52
|
</span>
|
|
53
53
|
)}
|
|
54
54
|
<hr className="border-border my-1" />
|
|
55
|
-
<div className="text-xs">
|
|
55
|
+
<div className="text-xs text-muted-foreground">
|
|
56
|
+
{responses[tabIndex].description}
|
|
57
|
+
</div>
|
|
56
58
|
</SidecarBox.Body>
|
|
57
59
|
</SidecarBox.Root>
|
|
58
60
|
);
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
-
import { ListPlusIcon } from "lucide-react";
|
|
3
|
-
import { useState } from "react";
|
|
4
1
|
import { Markdown } from "../../components/Markdown.js";
|
|
5
2
|
import { SchemaObject } from "../../oas/parser/index.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { objectEntries } from "../../util/objectEntries.js";
|
|
4
|
+
import { SchemaListViewItemGroup } from "./SchemaListViewItemGroup.js";
|
|
5
|
+
import { SchemaProseClasses } from "./util/prose.js";
|
|
8
6
|
|
|
9
7
|
export const SchemaListView = ({
|
|
10
8
|
name,
|
|
@@ -39,190 +37,25 @@ export const SchemaListView = ({
|
|
|
39
37
|
);
|
|
40
38
|
|
|
41
39
|
return (
|
|
42
|
-
<div
|
|
43
|
-
className={cn(
|
|
44
|
-
"not-prose",
|
|
45
|
-
level > 0 && "border border-border rounded text-sm",
|
|
46
|
-
)}
|
|
47
|
-
>
|
|
40
|
+
<div className="flex flex-col gap-2.5">
|
|
48
41
|
{(schema.title ?? name) && (
|
|
49
42
|
<div className="ml-2 my-1 font-bold">{schema.title ?? name}</div>
|
|
50
43
|
)}
|
|
51
44
|
{level === 0 && schema.description && (
|
|
52
|
-
<
|
|
53
|
-
)}
|
|
54
|
-
<ul>
|
|
55
|
-
{Object.entries(groups).map(([group, properties]) => {
|
|
56
|
-
return (
|
|
57
|
-
<SchemaListViewItemGroup
|
|
58
|
-
key={group}
|
|
59
|
-
defaultOpen={defaultOpen}
|
|
60
|
-
group={group as any}
|
|
61
|
-
nestingLevel={level}
|
|
62
|
-
properties={properties}
|
|
63
|
-
required={schema.required ?? []}
|
|
64
|
-
/>
|
|
65
|
-
);
|
|
66
|
-
})}
|
|
67
|
-
</ul>
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const SchemaListViewItemGroup = ({
|
|
73
|
-
group,
|
|
74
|
-
properties,
|
|
75
|
-
nestingLevel,
|
|
76
|
-
required,
|
|
77
|
-
defaultOpen = false,
|
|
78
|
-
}: {
|
|
79
|
-
group: "optional" | "required" | "deprecated";
|
|
80
|
-
defaultOpen?: boolean;
|
|
81
|
-
properties: [string, SchemaObject][];
|
|
82
|
-
nestingLevel: number;
|
|
83
|
-
required: string[];
|
|
84
|
-
}) => {
|
|
85
|
-
const notCollapsible =
|
|
86
|
-
defaultOpen ||
|
|
87
|
-
group === "required" ||
|
|
88
|
-
properties.length === 1 ||
|
|
89
|
-
nestingLevel === 0;
|
|
90
|
-
const [open, setOpen] = useState(notCollapsible);
|
|
91
|
-
if (properties.length === 0) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return (
|
|
96
|
-
<Collapsible.Root
|
|
97
|
-
className="CollapsibleRoot"
|
|
98
|
-
open={open}
|
|
99
|
-
onOpenChange={setOpen}
|
|
100
|
-
>
|
|
101
|
-
{!open && (
|
|
102
|
-
<Collapsible.Trigger
|
|
103
|
-
className={cn(
|
|
104
|
-
"py-2 hover:bg-muted w-full",
|
|
105
|
-
group === "optional" && "font-semibold",
|
|
106
|
-
group === "deprecated" && "text-muted-foreground",
|
|
107
|
-
)}
|
|
108
|
-
>
|
|
109
|
-
{properties.length} {group} fields
|
|
110
|
-
</Collapsible.Trigger>
|
|
45
|
+
<Markdown className={SchemaProseClasses} content={schema.description} />
|
|
111
46
|
)}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
47
|
+
<ul className="border-border border rounded overflow-hidden">
|
|
48
|
+
{objectEntries(groups).map(([group, properties]) => (
|
|
49
|
+
<SchemaListViewItemGroup
|
|
50
|
+
key={group}
|
|
51
|
+
defaultOpen={defaultOpen}
|
|
52
|
+
group={group}
|
|
53
|
+
nestingLevel={level}
|
|
54
|
+
properties={properties ?? []}
|
|
55
|
+
required={schema.required ?? []}
|
|
121
56
|
/>
|
|
122
57
|
))}
|
|
123
|
-
</
|
|
124
|
-
</Collapsible.Root>
|
|
125
|
-
);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const SchemaListViewItem = ({
|
|
129
|
-
propertyName,
|
|
130
|
-
property,
|
|
131
|
-
nestingLevel,
|
|
132
|
-
isRequired,
|
|
133
|
-
}: {
|
|
134
|
-
propertyName: string;
|
|
135
|
-
isRequired: boolean;
|
|
136
|
-
property: SchemaObject;
|
|
137
|
-
nestingLevel: number;
|
|
138
|
-
}) => {
|
|
139
|
-
return (
|
|
140
|
-
<div
|
|
141
|
-
key={propertyName}
|
|
142
|
-
className={cn(
|
|
143
|
-
nestingLevel > 0 ? "py-2" : "py-4",
|
|
144
|
-
"px-2 border-t border-border bg-border/20 hover:bg-border/30 flex gap-1 flex-col text-sm",
|
|
145
|
-
property.deprecated && "opacity-50",
|
|
146
|
-
)}
|
|
147
|
-
>
|
|
148
|
-
<div className="flex items-center gap-2 relative">
|
|
149
|
-
<code>
|
|
150
|
-
{propertyName} {property.title}
|
|
151
|
-
</code>
|
|
152
|
-
|
|
153
|
-
{property.type && (
|
|
154
|
-
<span className="text-xs text-muted-foreground">{property.type}</span>
|
|
155
|
-
)}
|
|
156
|
-
{property.deprecated && (
|
|
157
|
-
<span className="text-xs text-muted-foreground">Deprecated</span>
|
|
158
|
-
)}
|
|
159
|
-
{!isRequired && (
|
|
160
|
-
<span className="py-px px-1.5 font-medium text-xs border border-border rounded-lg">
|
|
161
|
-
optional {property.required}
|
|
162
|
-
</span>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
165
|
-
{property.description && (
|
|
166
|
-
<Markdown
|
|
167
|
-
content={property.description}
|
|
168
|
-
className="text-sm leading-normal line-clamp-4 "
|
|
169
|
-
/>
|
|
170
|
-
)}
|
|
171
|
-
|
|
172
|
-
{property.enum && (
|
|
173
|
-
<span className="text-sm text-muted-foreground flex gap-1 flex-wrap items-center">
|
|
174
|
-
<span>Possible values</span>
|
|
175
|
-
{property.enum
|
|
176
|
-
.filter((value) => value)
|
|
177
|
-
.map((value) => (
|
|
178
|
-
<span
|
|
179
|
-
key={value}
|
|
180
|
-
className="font-mono text-xs border-border border bg-muted rounded px-1"
|
|
181
|
-
>
|
|
182
|
-
{value}
|
|
183
|
-
</span>
|
|
184
|
-
))
|
|
185
|
-
.slice(0, 4)}
|
|
186
|
-
{property.enum.length > 4 && (
|
|
187
|
-
<span className="font-mono text-xs border-border border bg-muted rounded px-1">
|
|
188
|
-
...
|
|
189
|
-
</span>
|
|
190
|
-
)}
|
|
191
|
-
</span>
|
|
192
|
-
)}
|
|
193
|
-
|
|
194
|
-
<Collapsible.Root className="CollapsibleRoot" defaultOpen={false}>
|
|
195
|
-
{property.type === "object" ||
|
|
196
|
-
(property.type === "array" && property.items.type === "object") ? (
|
|
197
|
-
<Collapsible.Trigger asChild>
|
|
198
|
-
<Button variant="ghost" size="sm">
|
|
199
|
-
Show nested fields
|
|
200
|
-
<ListPlusIcon size={18} className="ml-1.5" />
|
|
201
|
-
</Button>
|
|
202
|
-
</Collapsible.Trigger>
|
|
203
|
-
) : null}
|
|
204
|
-
|
|
205
|
-
<Collapsible.Content>
|
|
206
|
-
{property.type === "object" && (
|
|
207
|
-
<div className="mt-2.5">
|
|
208
|
-
<SchemaListView
|
|
209
|
-
schema={property}
|
|
210
|
-
level={nestingLevel + 1}
|
|
211
|
-
defaultOpen
|
|
212
|
-
/>
|
|
213
|
-
</div>
|
|
214
|
-
)}
|
|
215
|
-
{property.type === "array" && property.items.type === "object" && (
|
|
216
|
-
<div className="mt-2.5">
|
|
217
|
-
<SchemaListView
|
|
218
|
-
schema={property.items}
|
|
219
|
-
defaultOpen
|
|
220
|
-
level={nestingLevel + 1}
|
|
221
|
-
/>
|
|
222
|
-
</div>
|
|
223
|
-
)}
|
|
224
|
-
</Collapsible.Content>
|
|
225
|
-
</Collapsible.Root>
|
|
58
|
+
</ul>
|
|
226
59
|
</div>
|
|
227
60
|
);
|
|
228
61
|
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
+
import { ListPlusIcon } from "lucide-react";
|
|
3
|
+
import { Markdown } from "../../components/Markdown.js";
|
|
4
|
+
import { SchemaObject } from "../../oas/parser/index.js";
|
|
5
|
+
import { Button } from "../../ui/Button.js";
|
|
6
|
+
import { cn } from "../../util/cn.js";
|
|
7
|
+
import { SchemaListView } from "./SchemaListView.js";
|
|
8
|
+
|
|
9
|
+
export const SchemaListViewItem = ({
|
|
10
|
+
propertyName,
|
|
11
|
+
property,
|
|
12
|
+
nestingLevel,
|
|
13
|
+
isRequired,
|
|
14
|
+
}: {
|
|
15
|
+
propertyName: string;
|
|
16
|
+
isRequired: boolean;
|
|
17
|
+
property: SchemaObject;
|
|
18
|
+
nestingLevel: number;
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
key={propertyName}
|
|
23
|
+
className={cn(
|
|
24
|
+
"p-4 bg-border/20 hover:bg-border/30 flex gap-1 flex-col text-sm",
|
|
25
|
+
property.deprecated && "opacity-50",
|
|
26
|
+
)}
|
|
27
|
+
>
|
|
28
|
+
<div className="flex items-center gap-2 relative">
|
|
29
|
+
<code>
|
|
30
|
+
{propertyName} {property.title}
|
|
31
|
+
</code>
|
|
32
|
+
|
|
33
|
+
{property.type && (
|
|
34
|
+
<span className="text-muted-foreground">{property.type}</span>
|
|
35
|
+
)}
|
|
36
|
+
{property.deprecated && (
|
|
37
|
+
<span className="text-muted-foreground">Deprecated</span>
|
|
38
|
+
)}
|
|
39
|
+
{!isRequired && (
|
|
40
|
+
<span className="py-px px-1.5 font-medium border border-border rounded-lg">
|
|
41
|
+
optional {property.required}
|
|
42
|
+
</span>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
{property.description && (
|
|
46
|
+
<Markdown
|
|
47
|
+
content={property.description}
|
|
48
|
+
className="text-sm leading-normal line-clamp-4 "
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
|
|
52
|
+
{property.enum && (
|
|
53
|
+
<span className="text-sm text-muted-foreground flex gap-1 flex-wrap items-center">
|
|
54
|
+
<span>Possible values</span>
|
|
55
|
+
{/* Make values unique, some schemas have duplicates */}
|
|
56
|
+
{[...new Set(property.enum.filter((value) => value))]
|
|
57
|
+
.map((value) => (
|
|
58
|
+
<span
|
|
59
|
+
key={value}
|
|
60
|
+
className="font-mono text-xs border-border border bg-muted rounded px-1"
|
|
61
|
+
>
|
|
62
|
+
{value}
|
|
63
|
+
</span>
|
|
64
|
+
))
|
|
65
|
+
.slice(0, 4)}
|
|
66
|
+
{property.enum.length > 4 && (
|
|
67
|
+
<span className="font-mono text-xs border-border border bg-muted rounded px-1">
|
|
68
|
+
...
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
</span>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
{(property.type === "object" &&
|
|
75
|
+
(property.properties?.length ??
|
|
76
|
+
Object.entries(property.additionalProperties ?? {}).length > 0)) ||
|
|
77
|
+
(property.type === "array" && property.items.type === "object") ? (
|
|
78
|
+
<Collapsible.Root className="CollapsibleRoot" defaultOpen={false}>
|
|
79
|
+
<Collapsible.Trigger asChild>
|
|
80
|
+
<Button variant="ghost" size="sm">
|
|
81
|
+
Show nested fields
|
|
82
|
+
<ListPlusIcon size={18} className="ml-1.5" />
|
|
83
|
+
</Button>
|
|
84
|
+
</Collapsible.Trigger>
|
|
85
|
+
|
|
86
|
+
<Collapsible.Content>
|
|
87
|
+
{property.type === "object" && (
|
|
88
|
+
<div className="mt-2.5">
|
|
89
|
+
<SchemaListView
|
|
90
|
+
schema={property}
|
|
91
|
+
level={nestingLevel + 1}
|
|
92
|
+
defaultOpen
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
{property.type === "array" && property.items.type === "object" && (
|
|
97
|
+
<div className="mt-2.5">
|
|
98
|
+
<SchemaListView
|
|
99
|
+
schema={property.items}
|
|
100
|
+
defaultOpen
|
|
101
|
+
level={nestingLevel + 1}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
</Collapsible.Content>
|
|
106
|
+
</Collapsible.Root>
|
|
107
|
+
) : null}
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { SchemaObject } from "../../oas/parser/index.js";
|
|
4
|
+
import { cn } from "../../util/cn.js";
|
|
5
|
+
import { SchemaListViewItem } from "./SchemaListViewItem.js";
|
|
6
|
+
|
|
7
|
+
export const SchemaListViewItemGroup = ({
|
|
8
|
+
group,
|
|
9
|
+
properties,
|
|
10
|
+
nestingLevel,
|
|
11
|
+
required,
|
|
12
|
+
defaultOpen = false,
|
|
13
|
+
}: {
|
|
14
|
+
group: "optional" | "required" | "deprecated";
|
|
15
|
+
defaultOpen?: boolean;
|
|
16
|
+
properties: [string, SchemaObject][];
|
|
17
|
+
nestingLevel: number;
|
|
18
|
+
required: string[];
|
|
19
|
+
}) => {
|
|
20
|
+
const notCollapsible =
|
|
21
|
+
defaultOpen ||
|
|
22
|
+
group === "required" ||
|
|
23
|
+
properties.length === 1 ||
|
|
24
|
+
nestingLevel === 0;
|
|
25
|
+
|
|
26
|
+
const [open, setOpen] = useState(notCollapsible);
|
|
27
|
+
|
|
28
|
+
if (properties.length === 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Collapsible.Root
|
|
34
|
+
className="CollapsibleRoot"
|
|
35
|
+
open={open}
|
|
36
|
+
onOpenChange={setOpen}
|
|
37
|
+
>
|
|
38
|
+
{!open && (
|
|
39
|
+
<Collapsible.Trigger
|
|
40
|
+
className={cn(
|
|
41
|
+
"py-2 hover:bg-muted w-full",
|
|
42
|
+
group === "optional" && "font-semibold",
|
|
43
|
+
group === "deprecated" && "text-muted-foreground",
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
{properties.length} {group} fields
|
|
47
|
+
</Collapsible.Trigger>
|
|
48
|
+
)}
|
|
49
|
+
|
|
50
|
+
<Collapsible.Content className="divide-y divide-border">
|
|
51
|
+
{properties.map(([propertyName, property]) => (
|
|
52
|
+
<SchemaListViewItem
|
|
53
|
+
key={propertyName}
|
|
54
|
+
property={property}
|
|
55
|
+
propertyName={propertyName}
|
|
56
|
+
nestingLevel={nestingLevel}
|
|
57
|
+
isRequired={required.includes(propertyName)}
|
|
58
|
+
/>
|
|
59
|
+
))}
|
|
60
|
+
</Collapsible.Content>
|
|
61
|
+
</Collapsible.Root>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
@@ -5,9 +5,9 @@ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
|
5
5
|
import type { SchemaObject } from "../../oas/parser/index.js";
|
|
6
6
|
import { cn } from "../../util/cn.js";
|
|
7
7
|
import { ColorizedParam } from "./ColorizedParam.js";
|
|
8
|
-
import { MakeRequest } from "./MakeRequest.js";
|
|
9
8
|
import { MethodTextColorMap } from "./MethodBadge.js";
|
|
10
9
|
import type { OperationListItemResult } from "./OperationList.js";
|
|
10
|
+
import { PlaygroundDialogWrapper } from "./PlaygroundDialogWrapper.js";
|
|
11
11
|
import { RequestBodySidecarBox } from "./RequestBodySidecarBox.js";
|
|
12
12
|
import { ResponsesSidecarBox } from "./ResponsesSidecarBox.js";
|
|
13
13
|
import * as SidecarBox from "./SidecarBox.js";
|
|
@@ -142,7 +142,7 @@ export const Sidecar = ({
|
|
|
142
142
|
{ value: "swift", label: "Swift" },
|
|
143
143
|
]}
|
|
144
144
|
/>
|
|
145
|
-
<
|
|
145
|
+
<PlaygroundDialogWrapper operation={operation} />
|
|
146
146
|
</div>
|
|
147
147
|
</SidecarBox.Head>
|
|
148
148
|
<SidecarBox.Body>
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
} from "./util/urql.js";
|
|
16
16
|
|
|
17
17
|
import { createSharedWorkerClient } from "virtual:zudoku-openapi-worker";
|
|
18
|
-
import type { createSharedWorkerClient as createSharedWorkerClientType } from "./worker/createSharedWorkerClient.js";
|
|
19
18
|
|
|
20
19
|
const OasContext = createContext<{ config: OasPluginConfig } | undefined>(
|
|
21
20
|
undefined,
|
|
@@ -85,11 +84,25 @@ export const openApiPlugin = (config: OasPluginConfig): DevPortalPlugin => {
|
|
|
85
84
|
url: config.server,
|
|
86
85
|
exchanges: [cacheExchange, fetchExchange],
|
|
87
86
|
})
|
|
88
|
-
:
|
|
89
|
-
typeof createSharedWorkerClientType
|
|
90
|
-
>);
|
|
87
|
+
: createSharedWorkerClient();
|
|
91
88
|
|
|
92
89
|
return {
|
|
90
|
+
getHead: () => {
|
|
91
|
+
if (config.type === "url") {
|
|
92
|
+
return (
|
|
93
|
+
<link
|
|
94
|
+
rel="preload"
|
|
95
|
+
href={config.input}
|
|
96
|
+
as="fetch"
|
|
97
|
+
crossOrigin="anonymous"
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (config.server) {
|
|
103
|
+
return <link rel="preconnect" href={config.server} />;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
93
106
|
getNavigation: async (path: string) => {
|
|
94
107
|
if (!matchPath({ path: basePath, end: false }, path)) {
|
|
95
108
|
return [];
|