zudoku 0.28.2 → 0.29.0
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/cli/common/output.js.map +1 -1
- package/dist/cli/dev/handler.js +5 -0
- package/dist/cli/dev/handler.js.map +1 -1
- package/dist/config/validators/common.d.ts +111 -0
- package/dist/config/validators/common.js +9 -6
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +42 -0
- package/dist/lib/authentication/state.d.ts +9 -0
- package/dist/lib/authentication/state.js +11 -0
- package/dist/lib/authentication/state.js.map +1 -1
- package/dist/lib/components/Autocomplete.d.ts +4 -3
- package/dist/lib/components/Autocomplete.js +2 -2
- package/dist/lib/components/Autocomplete.js.map +1 -1
- package/dist/lib/components/PathRenderer.js +23 -20
- package/dist/lib/components/PathRenderer.js.map +1 -1
- package/dist/lib/components/navigation/SidebarItem.js +1 -0
- package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
- package/dist/lib/oas/graphql/index.d.ts +7 -0
- package/dist/lib/oas/graphql/index.js +7 -6
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/plugins/openapi/Endpoint.js +6 -7
- package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +11 -7
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +4 -4
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/gql.d.ts +2 -2
- package/dist/lib/plugins/openapi/graphql/gql.js +2 -2
- package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
- package/dist/lib/plugins/openapi/graphql/graphql.d.ts +20 -4
- package/dist/lib/plugins/openapi/graphql/graphql.js +16 -2
- package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +57 -28
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +4 -2
- package/dist/lib/plugins/openapi/playground/Headers.d.ts +3 -2
- package/dist/lib/plugins/openapi/playground/Headers.js +42 -26
- package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +4 -0
- package/dist/lib/plugins/openapi/playground/ParamsGrid.js +2 -1
- package/dist/lib/plugins/openapi/playground/ParamsGrid.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.js +3 -3
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +1 -0
- package/dist/lib/plugins/openapi/playground/Playground.js +4 -4
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js +21 -21
- package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
- package/dist/lib/ui/Input.d.ts +1 -2
- package/dist/lib/ui/Input.js.map +1 -1
- package/dist/lib/util/useScrollToAnchor.js +1 -1
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/lib/util/useScrollToTop.js +6 -4
- package/dist/lib/util/useScrollToTop.js.map +1 -1
- package/dist/vite/plugin-api.js +13 -6
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-mdx.js +18 -12
- package/dist/vite/plugin-mdx.js.map +1 -1
- package/dist/vite/plugin.js.map +1 -1
- package/lib/{Markdown-LcMEZ0Sn.js → Markdown-8mv9nhGd.js} +3338 -3360
- package/lib/Markdown-8mv9nhGd.js.map +1 -0
- package/lib/{MdxPage-DkH3V4hV.js → MdxPage-BalfwlsD.js} +3 -3
- package/lib/{MdxPage-DkH3V4hV.js.map → MdxPage-BalfwlsD.js.map} +1 -1
- package/lib/{OperationList-wzZNceUl.js → OperationList-B3VX94x4.js} +500 -493
- package/lib/OperationList-B3VX94x4.js.map +1 -0
- package/lib/{Select-DJkXPPD0.js → Select-BcAbBUmk.js} +2 -2
- package/lib/{Select-DJkXPPD0.js.map → Select-BcAbBUmk.js.map} +1 -1
- package/lib/{SlotletProvider-D1t2ePCI.js → SlotletProvider-D0mFmGJu.js} +2 -2
- package/lib/{SlotletProvider-D1t2ePCI.js.map → SlotletProvider-D0mFmGJu.js.map} +1 -1
- package/lib/{createServer-DIztAu7i.js → createServer-E3cXjB0P.js} +4 -6
- package/lib/{createServer-DIztAu7i.js.map → createServer-E3cXjB0P.js.map} +1 -1
- package/lib/{hook-CiX69UZ6.js → hook-NIpDSpau.js} +2 -2
- package/lib/{hook-CiX69UZ6.js.map → hook-NIpDSpau.js.map} +1 -1
- package/lib/{index-DrR58fsJ.js → index-P0YUtHIb.js} +802 -745
- package/lib/index-P0YUtHIb.js.map +1 -0
- package/lib/state-bfQxaDxU.js +211 -0
- package/lib/{state-mM7uaXTW.js.map → state-bfQxaDxU.js.map} +1 -1
- package/lib/ui/Input.js.map +1 -1
- package/lib/{useScrollToAnchor-DYGn1MT9.js → useScrollToAnchor-BVCQSeKB.js} +29 -28
- package/lib/{useScrollToAnchor-DYGn1MT9.js.map → useScrollToAnchor-BVCQSeKB.js.map} +1 -1
- package/lib/zudoku.auth-auth0.js +1 -1
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +1 -1
- package/lib/zudoku.components.js +348 -347
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-api-catalog.js +2 -2
- package/lib/zudoku.plugin-api-keys.js +3 -3
- package/lib/zudoku.plugin-custom-pages.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +2 -2
- package/package.json +2 -1
- package/src/app/demo-cdn.html +31 -31
- package/src/lib/authentication/state.ts +18 -0
- package/src/lib/components/Autocomplete.tsx +6 -4
- package/src/lib/components/PathRenderer.tsx +6 -4
- package/src/lib/components/navigation/SidebarItem.tsx +1 -0
- package/src/lib/oas/graphql/index.ts +10 -9
- package/src/lib/plugins/openapi/Endpoint.tsx +11 -9
- package/src/lib/plugins/openapi/OperationList.tsx +16 -10
- package/src/lib/plugins/openapi/Sidecar.tsx +4 -4
- package/src/lib/plugins/openapi/graphql/gql.ts +4 -4
- package/src/lib/plugins/openapi/graphql/graphql.ts +30 -6
- package/src/lib/plugins/openapi/index.tsx +74 -41
- package/src/lib/plugins/openapi/interfaces.ts +5 -10
- package/src/lib/plugins/openapi/playground/Headers.tsx +125 -89
- package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +6 -1
- package/src/lib/plugins/openapi/playground/PathParams.tsx +9 -9
- package/src/lib/plugins/openapi/playground/Playground.tsx +7 -4
- package/src/lib/plugins/openapi/playground/QueryParams.tsx +88 -86
- package/src/lib/ui/Input.tsx +1 -2
- package/src/lib/util/useScrollToAnchor.ts +1 -1
- package/src/lib/util/useScrollToTop.ts +8 -3
- package/lib/Markdown-LcMEZ0Sn.js.map +0 -1
- package/lib/OperationList-wzZNceUl.js.map +0 -1
- package/lib/index-DrR58fsJ.js.map +0 -1
- package/lib/state-mM7uaXTW.js +0 -202
|
@@ -26,14 +26,20 @@ const GetCategoriesQuery = graphql(`
|
|
|
26
26
|
`);
|
|
27
27
|
|
|
28
28
|
const GetOperationsQuery = graphql(`
|
|
29
|
-
query GetOperations(
|
|
30
|
-
$input: JSON!
|
|
31
|
-
$type: SchemaType!
|
|
32
|
-
$tag: String
|
|
33
|
-
$untagged: Boolean
|
|
34
|
-
) {
|
|
29
|
+
query GetOperations($input: JSON!, $type: SchemaType!, $tag: String) {
|
|
35
30
|
schema(input: $input, type: $type) {
|
|
36
|
-
operations(tag: $tag
|
|
31
|
+
operations(tag: $tag) {
|
|
32
|
+
slug
|
|
33
|
+
deprecated
|
|
34
|
+
method
|
|
35
|
+
summary
|
|
36
|
+
operationId
|
|
37
|
+
path
|
|
38
|
+
tags {
|
|
39
|
+
name
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
untagged: operations(untagged: true) {
|
|
37
43
|
slug
|
|
38
44
|
deprecated
|
|
39
45
|
method
|
|
@@ -138,7 +144,7 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
|
|
|
138
144
|
);
|
|
139
145
|
const version = urlVersion ?? Object.keys(config.input).at(0);
|
|
140
146
|
|
|
141
|
-
const
|
|
147
|
+
const tagData = await client.fetch(GetCategoriesQuery, {
|
|
142
148
|
type: config.type,
|
|
143
149
|
input: config.type === "file" ? config.input[version!] : config.input,
|
|
144
150
|
});
|
|
@@ -150,42 +156,69 @@ export const openApiPlugin = (config: OpenApiPluginOptions): ZudokuPlugin => {
|
|
|
150
156
|
const operationsData = await client.fetch(GetOperationsQuery, {
|
|
151
157
|
type: config.type,
|
|
152
158
|
input: config.type === "file" ? config.input[version!] : config.input,
|
|
153
|
-
tag,
|
|
154
|
-
untagged: tag === undefined,
|
|
159
|
+
tag: !config.loadTags ? tag : undefined,
|
|
155
160
|
});
|
|
156
161
|
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
162
|
+
const categories = tagData.schema.tags.flatMap<SidebarItem>((tag) => {
|
|
163
|
+
const categoryLink = joinUrl(basePath, urlVersion, slugify(tag.name));
|
|
164
|
+
|
|
165
|
+
const operations = operationsData.schema.operations
|
|
166
|
+
.filter(
|
|
167
|
+
(operation) =>
|
|
168
|
+
operation.tags?.length !== 0 &&
|
|
169
|
+
operation.tags?.map((t) => t.name).includes(tag.name),
|
|
170
|
+
)
|
|
171
|
+
.map((operation) => ({
|
|
172
|
+
type: "link" as const,
|
|
173
|
+
label: operation.summary ?? operation.path,
|
|
174
|
+
href: `${categoryLink}#${operation.slug}`,
|
|
175
|
+
badge: {
|
|
176
|
+
label: operation.method,
|
|
177
|
+
color: MethodColorMap[operation.method.toLowerCase()]!,
|
|
178
|
+
invert: true,
|
|
179
|
+
} as const,
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
if (config.loadTags && operations.length === 0) {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
type: "category",
|
|
188
|
+
label: tag.name,
|
|
189
|
+
link: {
|
|
190
|
+
type: "doc" as const,
|
|
191
|
+
id: categoryLink,
|
|
192
|
+
label: tag.name,
|
|
193
|
+
},
|
|
194
|
+
collapsible: config.loadTags,
|
|
195
|
+
collapsed: !config.loadTags,
|
|
196
|
+
items: operations,
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const { untagged } = operationsData.schema;
|
|
201
|
+
|
|
202
|
+
if (untagged.length > 0) {
|
|
203
|
+
const categoryLink = joinUrl(basePath, urlVersion, UNTAGGED_PATH);
|
|
204
|
+
|
|
205
|
+
categories.push({
|
|
206
|
+
type: "category",
|
|
207
|
+
label: "Other endpoints",
|
|
208
|
+
link: {
|
|
209
|
+
type: "doc" as const,
|
|
210
|
+
id: categoryLink,
|
|
211
|
+
label: "Other endpoints",
|
|
212
|
+
},
|
|
213
|
+
collapsible: config.loadTags,
|
|
214
|
+
collapsed: !config.loadTags,
|
|
215
|
+
items: untagged.map((operation) => ({
|
|
216
|
+
type: "link" as const,
|
|
217
|
+
label: operation.summary ?? operation.path,
|
|
218
|
+
href: `${categoryLink}#${operation.slug}`,
|
|
219
|
+
})),
|
|
188
220
|
});
|
|
221
|
+
}
|
|
189
222
|
|
|
190
223
|
return categories;
|
|
191
224
|
} catch {
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
+
type DynamicInput = () => Promise<unknown>;
|
|
2
|
+
|
|
1
3
|
type OasSource =
|
|
2
4
|
| { type: "url"; input: string }
|
|
3
|
-
| {
|
|
4
|
-
type: "file";
|
|
5
|
-
input: {
|
|
6
|
-
[version: string]: () => Promise<unknown>;
|
|
7
|
-
};
|
|
8
|
-
}
|
|
5
|
+
| { type: "file"; input: { [version: string]: DynamicInput } }
|
|
9
6
|
| { type: "raw"; input: string };
|
|
10
7
|
|
|
11
8
|
export type ContextOasSource =
|
|
12
9
|
| { type: "url"; input: string }
|
|
13
|
-
| {
|
|
14
|
-
type: "file";
|
|
15
|
-
input: () => Promise<unknown>;
|
|
16
|
-
}
|
|
10
|
+
| { type: "file"; input: DynamicInput }
|
|
17
11
|
| { type: "raw"; input: string };
|
|
18
12
|
|
|
19
13
|
export type OasPluginConfig = {
|
|
@@ -21,6 +15,7 @@ export type OasPluginConfig = {
|
|
|
21
15
|
navigationId?: string;
|
|
22
16
|
skipPreload?: boolean;
|
|
23
17
|
tagPages?: Array<string>;
|
|
18
|
+
loadTags?: boolean;
|
|
24
19
|
} & OasPluginConfigOptions &
|
|
25
20
|
OasSource;
|
|
26
21
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { XIcon } from "lucide-react";
|
|
2
|
-
import { useRef } from "react";
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
import {
|
|
4
4
|
Control,
|
|
5
5
|
Controller,
|
|
@@ -11,8 +11,8 @@ import { Checkbox } from "zudoku/ui/Checkbox.js";
|
|
|
11
11
|
import { Autocomplete } from "../../../components/Autocomplete.js";
|
|
12
12
|
import { Button } from "../../../ui/Button.js";
|
|
13
13
|
import { Input } from "../../../ui/Input.js";
|
|
14
|
-
import ParamsGrid from "./ParamsGrid.js";
|
|
15
|
-
import { type PlaygroundForm } from "./Playground.js";
|
|
14
|
+
import ParamsGrid, { ParamsGridItem } from "./ParamsGrid.js";
|
|
15
|
+
import { Header, type PlaygroundForm } from "./Playground.js";
|
|
16
16
|
|
|
17
17
|
const headerOptions = Object.freeze([
|
|
18
18
|
"Accept",
|
|
@@ -43,22 +43,31 @@ const headerOptions = Object.freeze([
|
|
|
43
43
|
"X-Requested-With",
|
|
44
44
|
]);
|
|
45
45
|
|
|
46
|
-
export const Headers = ({
|
|
47
|
-
|
|
46
|
+
export const Headers = ({
|
|
47
|
+
control,
|
|
48
|
+
headers: schemaHeaders,
|
|
49
|
+
}: {
|
|
50
|
+
control: Control<PlaygroundForm>;
|
|
51
|
+
headers: Header[];
|
|
52
|
+
}) => {
|
|
53
|
+
const { fields, append, remove } = useFieldArray<PlaygroundForm, "headers">({
|
|
48
54
|
control,
|
|
49
55
|
name: "headers",
|
|
50
56
|
});
|
|
51
|
-
const { setValue } = useFormContext<PlaygroundForm>();
|
|
57
|
+
const { setValue, watch } = useFormContext<PlaygroundForm>();
|
|
52
58
|
const valueRefs = useRef<Array<HTMLInputElement | null>>([]);
|
|
53
59
|
const nameRefs = useRef<Array<HTMLInputElement | null>>([]);
|
|
60
|
+
const watchedHeaders = watch("headers");
|
|
54
61
|
|
|
55
|
-
const addNewHeader = () => {
|
|
56
|
-
append({
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
const addNewHeader = useCallback(() => {
|
|
63
|
+
append({ name: "", value: "", active: false });
|
|
64
|
+
}, [append]);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (watchedHeaders.length === 0) {
|
|
68
|
+
addNewHeader();
|
|
69
|
+
}
|
|
70
|
+
}, [watchedHeaders, addNewHeader]);
|
|
62
71
|
|
|
63
72
|
const handleHeaderEnter = (index: number) => {
|
|
64
73
|
valueRefs.current[index]?.focus();
|
|
@@ -69,86 +78,113 @@ export const Headers = ({ control }: { control: Control<PlaygroundForm> }) => {
|
|
|
69
78
|
requestAnimationFrame(() => nameRefs.current[index + 1]?.focus());
|
|
70
79
|
};
|
|
71
80
|
|
|
81
|
+
const missingHeaders = schemaHeaders
|
|
82
|
+
.filter((h) => !watchedHeaders.some((f) => f.name === h.name))
|
|
83
|
+
.map(({ name }) => name);
|
|
84
|
+
|
|
72
85
|
return (
|
|
73
86
|
<div className="flex flex-col gap-2">
|
|
74
87
|
<Card className="overflow-hidden">
|
|
75
88
|
<ParamsGrid>
|
|
76
|
-
{fields.map((
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
89
|
+
{fields.map((field, i) => {
|
|
90
|
+
const currentHeader = schemaHeaders.find(
|
|
91
|
+
(h) => h.name === watch(`headers.${i}.name`),
|
|
92
|
+
);
|
|
93
|
+
return (
|
|
94
|
+
<ParamsGridItem key={field.id}>
|
|
95
|
+
<div className="flex items-center gap-2 ">
|
|
96
|
+
<Controller
|
|
97
|
+
control={control}
|
|
98
|
+
name={`headers.${i}.active`}
|
|
99
|
+
render={({ field }) => (
|
|
100
|
+
<Checkbox
|
|
101
|
+
variant="outline"
|
|
102
|
+
id={`headers.${i}.active`}
|
|
103
|
+
checked={field.value}
|
|
104
|
+
onCheckedChange={(checked) => {
|
|
105
|
+
field.onChange(checked);
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
/>
|
|
110
|
+
<Controller
|
|
111
|
+
control={control}
|
|
112
|
+
name={`headers.${i}.name`}
|
|
113
|
+
render={({ field }) => (
|
|
114
|
+
<Autocomplete
|
|
115
|
+
{...field}
|
|
116
|
+
placeholder="Name"
|
|
117
|
+
className="border-0 shadow-none bg-transparent text-xs font-mono"
|
|
118
|
+
options={[...missingHeaders, ...headerOptions]}
|
|
119
|
+
onEnterPress={() => handleHeaderEnter(i)}
|
|
120
|
+
onChange={(e) => {
|
|
121
|
+
field.onChange(e);
|
|
122
|
+
setValue(`headers.${i}.active`, true);
|
|
123
|
+
}}
|
|
124
|
+
ref={(el) => {
|
|
125
|
+
nameRefs.current[i] = el;
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
)}
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
<div className="flex items-center gap-2">
|
|
132
|
+
<Controller
|
|
133
|
+
control={control}
|
|
134
|
+
name={`headers.${i}.value`}
|
|
135
|
+
render={({ field }) => {
|
|
136
|
+
const hasEnum =
|
|
137
|
+
currentHeader?.enum && currentHeader.enum.length > 0;
|
|
138
|
+
|
|
139
|
+
if (!hasEnum) {
|
|
140
|
+
return (
|
|
141
|
+
<Input
|
|
142
|
+
placeholder="Value"
|
|
143
|
+
className="w-full border-0 shadow-none text-xs font-mono focus-visible:ring-0"
|
|
144
|
+
{...field}
|
|
145
|
+
ref={(el) => {
|
|
146
|
+
valueRefs.current[i] = el;
|
|
147
|
+
}}
|
|
148
|
+
onKeyDown={(e) => {
|
|
149
|
+
if (
|
|
150
|
+
e.key === "Enter" &&
|
|
151
|
+
e.currentTarget.value.trim()
|
|
152
|
+
) {
|
|
153
|
+
handleValueEnter(i);
|
|
154
|
+
}
|
|
155
|
+
}}
|
|
156
|
+
autoComplete="off"
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<Autocomplete
|
|
163
|
+
shouldFilter={false}
|
|
164
|
+
value={field.value}
|
|
165
|
+
options={currentHeader.enum ?? []}
|
|
166
|
+
onChange={(e) => {
|
|
167
|
+
field.onChange(e);
|
|
168
|
+
setValue(`headers.${i}.active`, true);
|
|
169
|
+
}}
|
|
170
|
+
className="font-mono text-xs border-0"
|
|
171
|
+
/>
|
|
172
|
+
);
|
|
173
|
+
}}
|
|
174
|
+
/>
|
|
175
|
+
<Button
|
|
176
|
+
size="icon"
|
|
177
|
+
variant="ghost"
|
|
178
|
+
className="text-muted-foreground opacity-0 group-hover:opacity-100 rounded-full w-8 h-7"
|
|
179
|
+
onClick={() => remove(i)}
|
|
180
|
+
type="button"
|
|
181
|
+
>
|
|
182
|
+
<XIcon size={16} />
|
|
183
|
+
</Button>
|
|
184
|
+
</div>
|
|
185
|
+
</ParamsGridItem>
|
|
186
|
+
);
|
|
187
|
+
})}
|
|
152
188
|
</ParamsGrid>
|
|
153
189
|
</Card>
|
|
154
190
|
<div className="text-end">
|
|
@@ -2,7 +2,12 @@ import createVariantComponent from "../../../util/createVariantComponent.js";
|
|
|
2
2
|
|
|
3
3
|
const ParamsGrid = createVariantComponent(
|
|
4
4
|
"div",
|
|
5
|
-
"
|
|
5
|
+
"grid grid-cols-[2fr_3fr] gap-2 items-center",
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
export const ParamsGridItem = createVariantComponent(
|
|
9
|
+
"div",
|
|
10
|
+
"group hover:bg-accent px-3 grid col-span-full grid-cols-subgrid",
|
|
6
11
|
);
|
|
7
12
|
|
|
8
13
|
export default ParamsGrid;
|
|
@@ -2,7 +2,7 @@ import { Control, Controller, useFieldArray } from "react-hook-form";
|
|
|
2
2
|
import { Card } from "zudoku/ui/Card.js";
|
|
3
3
|
import { Input } from "../../../ui/Input.js";
|
|
4
4
|
import { ColorizedParam } from "../ColorizedParam.js";
|
|
5
|
-
import ParamsGrid from "./ParamsGrid.js";
|
|
5
|
+
import ParamsGrid, { ParamsGridItem } from "./ParamsGrid.js";
|
|
6
6
|
import type { PlaygroundForm } from "./Playground.js";
|
|
7
7
|
|
|
8
8
|
export const PathParams = ({
|
|
@@ -10,7 +10,7 @@ export const PathParams = ({
|
|
|
10
10
|
}: {
|
|
11
11
|
control: Control<PlaygroundForm>;
|
|
12
12
|
}) => {
|
|
13
|
-
const { fields } = useFieldArray<PlaygroundForm>({
|
|
13
|
+
const { fields } = useFieldArray<PlaygroundForm, "pathParams">({
|
|
14
14
|
control,
|
|
15
15
|
name: "pathParams",
|
|
16
16
|
});
|
|
@@ -18,16 +18,16 @@ export const PathParams = ({
|
|
|
18
18
|
return (
|
|
19
19
|
<Card className="rounded-lg">
|
|
20
20
|
<ParamsGrid>
|
|
21
|
-
{fields.map((
|
|
22
|
-
|
|
21
|
+
{fields.map((field, i) => (
|
|
22
|
+
<ParamsGridItem key={field.id}>
|
|
23
23
|
<Controller
|
|
24
24
|
control={control}
|
|
25
25
|
name={`pathParams.${i}.name`}
|
|
26
26
|
render={() => (
|
|
27
|
-
<div>
|
|
27
|
+
<div className="flex items-center">
|
|
28
28
|
<ColorizedParam
|
|
29
|
-
slug={
|
|
30
|
-
name={
|
|
29
|
+
slug={field.name}
|
|
30
|
+
name={field.name}
|
|
31
31
|
className="font-mono text-xs px-2"
|
|
32
32
|
/>
|
|
33
33
|
</div>
|
|
@@ -43,12 +43,12 @@ export const PathParams = ({
|
|
|
43
43
|
{...field}
|
|
44
44
|
required
|
|
45
45
|
placeholder="Enter value"
|
|
46
|
-
className="w-full border-0 shadow-none text-xs font-mono
|
|
46
|
+
className="w-full border-0 shadow-none text-xs font-mono focus-visible:ring-0"
|
|
47
47
|
/>
|
|
48
48
|
)}
|
|
49
49
|
/>
|
|
50
50
|
</div>
|
|
51
|
-
|
|
51
|
+
</ParamsGridItem>
|
|
52
52
|
))}
|
|
53
53
|
</ParamsGrid>
|
|
54
54
|
</Card>
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
SelectValue,
|
|
16
16
|
} from "zudoku/ui/Select.js";
|
|
17
17
|
import { Textarea } from "zudoku/ui/Textarea.js";
|
|
18
|
-
import {
|
|
18
|
+
import { useSelectedServer } from "../../../authentication/state.js";
|
|
19
19
|
import { useApiIdentities } from "../../../components/context/ZudokuContext.js";
|
|
20
20
|
import { Card } from "../../../ui/Card.js";
|
|
21
21
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/Tabs.js";
|
|
@@ -68,6 +68,7 @@ export type PlaygroundForm = {
|
|
|
68
68
|
name: string;
|
|
69
69
|
value: string;
|
|
70
70
|
active: boolean;
|
|
71
|
+
enum?: string[];
|
|
71
72
|
}>;
|
|
72
73
|
identity?: string;
|
|
73
74
|
};
|
|
@@ -100,7 +101,7 @@ export type PlaygroundContentProps = {
|
|
|
100
101
|
|
|
101
102
|
export const Playground = ({
|
|
102
103
|
server,
|
|
103
|
-
servers,
|
|
104
|
+
servers = [],
|
|
104
105
|
url,
|
|
105
106
|
method,
|
|
106
107
|
headers = [],
|
|
@@ -109,7 +110,9 @@ export const Playground = ({
|
|
|
109
110
|
defaultBody = "",
|
|
110
111
|
examples,
|
|
111
112
|
}: PlaygroundContentProps) => {
|
|
112
|
-
const { selectedServer, setSelectedServer } =
|
|
113
|
+
const { selectedServer, setSelectedServer } = useSelectedServer(
|
|
114
|
+
servers.map((server) => ({ url: server })),
|
|
115
|
+
);
|
|
113
116
|
const [, startTransition] = useTransition();
|
|
114
117
|
const { register, control, handleSubmit, watch, setValue, ...form } =
|
|
115
118
|
useForm<PlaygroundForm>({
|
|
@@ -340,7 +343,7 @@ export const Playground = ({
|
|
|
340
343
|
</TabsList>
|
|
341
344
|
</div>
|
|
342
345
|
<TabsContent value="headers">
|
|
343
|
-
<Headers control={control} />
|
|
346
|
+
<Headers control={control} headers={headers} />
|
|
344
347
|
</TabsContent>
|
|
345
348
|
<TabsContent value="parameters">
|
|
346
349
|
{pathParams.length > 0 && (
|