docusaurus-theme-openapi-docs 4.7.1 → 5.0.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/lib/index.js +2 -0
- package/lib/markdown/schema.js +63 -9
- package/lib/theme/ApiExplorer/Accept/index.js +2 -1
- package/lib/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.js +16 -5
- package/lib/theme/ApiExplorer/Authorization/index.js +12 -18
- package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +0 -4
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +5 -1
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +190 -37
- package/lib/theme/ApiExplorer/Body/index.js +84 -13
- package/lib/theme/ApiExplorer/Body/slice.d.ts +136 -544
- package/lib/theme/ApiExplorer/CodeSnippets/index.d.ts +2 -1
- package/lib/theme/ApiExplorer/CodeSnippets/index.js +4 -0
- package/lib/theme/ApiExplorer/CodeTabs/index.js +15 -16
- package/lib/theme/ApiExplorer/ContentType/index.js +7 -2
- package/lib/theme/ApiExplorer/EncodingSelection/slice.d.ts +17 -0
- package/lib/theme/ApiExplorer/EncodingSelection/slice.js +29 -0
- package/lib/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.d.ts +12 -0
- package/lib/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.js +39 -0
- package/lib/theme/ApiExplorer/FormItem/_FormItem.scss +0 -5
- package/lib/theme/ApiExplorer/FormItem/index.d.ts +1 -4
- package/lib/theme/ApiExplorer/FormItem/index.js +2 -26
- package/lib/theme/ApiExplorer/FormLabel/_FormLabel.scss +4 -0
- package/lib/theme/ApiExplorer/FormLabel/index.d.ts +9 -0
- package/lib/theme/ApiExplorer/FormLabel/index.js +50 -0
- package/lib/theme/ApiExplorer/FormMultiSelect/index.d.ts +4 -1
- package/lib/theme/ApiExplorer/FormMultiSelect/index.js +97 -19
- package/lib/theme/ApiExplorer/FormSelect/index.d.ts +6 -1
- package/lib/theme/ApiExplorer/FormSelect/index.js +96 -15
- package/lib/theme/ApiExplorer/FormTextInput/index.d.ts +4 -1
- package/lib/theme/ApiExplorer/FormTextInput/index.js +71 -1
- package/lib/theme/ApiExplorer/MethodEndpoint/index.js +28 -0
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.d.ts +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +11 -3
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.d.ts +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.d.ts +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +6 -2
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.d.ts +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +6 -2
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.d.ts +4 -1
- package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.js +8 -3
- package/lib/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +0 -9
- package/lib/theme/ApiExplorer/ParamOptions/index.d.ts +10 -0
- package/lib/theme/ApiExplorer/ParamOptions/index.js +55 -5
- package/lib/theme/ApiExplorer/Request/_Request.scss +11 -0
- package/lib/theme/ApiExplorer/Request/index.js +19 -5
- package/lib/theme/ApiExplorer/Request/makeRequest.d.ts +3 -1
- package/lib/theme/ApiExplorer/Request/makeRequest.js +19 -3
- package/lib/theme/ApiExplorer/Response/_Response.scss +11 -0
- package/lib/theme/ApiExplorer/Response/index.js +98 -12
- package/lib/theme/ApiExplorer/Server/index.d.ts +4 -1
- package/lib/theme/ApiExplorer/Server/index.js +6 -3
- package/lib/theme/ApiExplorer/buildPostmanRequest.d.ts +4 -1
- package/lib/theme/ApiExplorer/buildPostmanRequest.js +46 -5
- package/lib/theme/ApiExplorer/index.js +1 -0
- package/lib/theme/ApiExplorer/persistenceMiddleware.d.ts +2 -0
- package/lib/theme/ApiItem/hooks.d.ts +1 -0
- package/lib/theme/ApiItem/index.js +2 -1
- package/lib/theme/ApiItem/store.d.ts +6 -0
- package/lib/theme/ApiItem/store.js +11 -7
- package/lib/theme/ApiTabs/index.js +10 -11
- package/lib/theme/DiscriminatorTabs/index.js +10 -11
- package/lib/theme/MimeTabs/index.js +10 -11
- package/lib/theme/OperationTabs/index.js +10 -11
- package/lib/theme/ParamsItem/index.js +27 -0
- package/lib/theme/RequestSchema/index.js +172 -109
- package/lib/theme/ResponseHeaders/index.js +0 -1
- package/lib/theme/Schema/index.d.ts +1 -1
- package/lib/theme/Schema/index.js +91 -23
- package/lib/theme/SchemaItem/index.js +6 -1
- package/lib/theme/SchemaTabs/index.d.ts +1 -1
- package/lib/theme/SchemaTabs/index.js +31 -12
- package/lib/theme/styles.scss +1 -0
- package/lib/theme/translationIds.d.ts +3 -0
- package/lib/theme/translationIds.js +3 -0
- package/package.json +9 -8
- package/src/index.ts +2 -0
- package/src/markdown/schema.ts +69 -13
- package/src/theme/ApiExplorer/Accept/index.tsx +2 -1
- package/src/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.tsx +15 -3
- package/src/theme/ApiExplorer/Authorization/index.tsx +27 -33
- package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +0 -5
- package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +115 -37
- package/src/theme/ApiExplorer/Body/index.tsx +85 -17
- package/src/theme/ApiExplorer/CodeSnippets/index.tsx +9 -1
- package/src/theme/ApiExplorer/CodeTabs/index.tsx +19 -19
- package/src/theme/ApiExplorer/ContentType/index.tsx +7 -4
- package/src/theme/ApiExplorer/EncodingSelection/slice.ts +31 -0
- package/src/theme/ApiExplorer/EncodingSelection/useResolvedEncoding.ts +43 -0
- package/src/theme/ApiExplorer/FormItem/_FormItem.scss +0 -5
- package/src/theme/ApiExplorer/FormItem/index.tsx +2 -16
- package/src/theme/ApiExplorer/FormLabel/_FormLabel.scss +4 -0
- package/src/theme/ApiExplorer/FormLabel/index.tsx +43 -0
- package/src/theme/ApiExplorer/FormMultiSelect/index.tsx +40 -20
- package/src/theme/ApiExplorer/FormSelect/index.tsx +41 -15
- package/src/theme/ApiExplorer/FormTextInput/index.tsx +15 -1
- package/src/theme/ApiExplorer/MethodEndpoint/index.tsx +21 -0
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +13 -2
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +12 -1
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +14 -2
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +14 -2
- package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +16 -3
- package/src/theme/ApiExplorer/ParamOptions/_ParamOptions.scss +0 -9
- package/src/theme/ApiExplorer/ParamOptions/index.tsx +97 -11
- package/src/theme/ApiExplorer/Request/_Request.scss +11 -0
- package/src/theme/ApiExplorer/Request/index.tsx +20 -8
- package/src/theme/ApiExplorer/Request/makeRequest.ts +19 -3
- package/src/theme/ApiExplorer/Response/_Response.scss +11 -0
- package/src/theme/ApiExplorer/Response/index.tsx +35 -14
- package/src/theme/ApiExplorer/Server/index.tsx +10 -3
- package/src/theme/ApiExplorer/buildPostmanRequest.ts +52 -5
- package/src/theme/ApiExplorer/index.tsx +1 -0
- package/src/theme/ApiItem/index.tsx +2 -1
- package/src/theme/ApiItem/store.ts +2 -0
- package/src/theme/ApiTabs/index.tsx +14 -19
- package/src/theme/DiscriminatorTabs/index.tsx +14 -19
- package/src/theme/MimeTabs/index.tsx +15 -19
- package/src/theme/OperationTabs/index.tsx +14 -19
- package/src/theme/ParamsItem/index.tsx +25 -0
- package/src/theme/RequestSchema/index.tsx +141 -83
- package/src/theme/ResponseHeaders/index.tsx +1 -2
- package/src/theme/Schema/index.tsx +112 -27
- package/src/theme/SchemaItem/index.tsx +6 -1
- package/src/theme/SchemaTabs/index.tsx +42 -21
- package/src/theme/styles.scss +1 -0
- package/src/theme/translationIds.ts +3 -0
- package/src/theme-classic.d.ts +25 -1
- package/src/types.d.ts +7 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
-
import React from "react";
|
|
8
|
+
import React, { useEffect, useState } from "react";
|
|
9
9
|
|
|
10
10
|
import FormFileUpload from "@theme/ApiExplorer/FormFileUpload";
|
|
11
|
+
import FormLabel from "@theme/ApiExplorer/FormLabel";
|
|
11
12
|
import FormSelect from "@theme/ApiExplorer/FormSelect";
|
|
12
13
|
import FormTextInput from "@theme/ApiExplorer/FormTextInput";
|
|
13
14
|
import LiveApp from "@theme/ApiExplorer/LiveEditor";
|
|
@@ -16,70 +17,139 @@ import type { SchemaObject } from "docusaurus-plugin-openapi-docs/src/openapi/ty
|
|
|
16
17
|
|
|
17
18
|
import FileArrayFormBodyItem from "../FileArrayFormBodyItem";
|
|
18
19
|
import { clearFormBodyKey, setFileFormBody, setStringFormBody } from "../slice";
|
|
20
|
+
import { setFieldEncoding } from "../../EncodingSelection/slice";
|
|
19
21
|
|
|
20
22
|
interface FormBodyItemProps {
|
|
21
23
|
schemaObject: SchemaObject;
|
|
22
24
|
id: string;
|
|
23
25
|
schema: SchemaObject;
|
|
26
|
+
label?: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
exampleValue?: SchemaObject["example"];
|
|
29
|
+
fieldEncoding?: string;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
export default function FormBodyItem({
|
|
27
33
|
schemaObject,
|
|
28
34
|
id,
|
|
29
35
|
schema,
|
|
36
|
+
label,
|
|
37
|
+
required,
|
|
38
|
+
exampleValue,
|
|
39
|
+
fieldEncoding,
|
|
30
40
|
}: FormBodyItemProps): React.JSX.Element {
|
|
31
41
|
const dispatch = useTypedDispatch();
|
|
32
42
|
|
|
43
|
+
// Parse comma-separated encoding contentType into selectable options
|
|
44
|
+
const encodingOptions = fieldEncoding
|
|
45
|
+
? fieldEncoding
|
|
46
|
+
.split(",")
|
|
47
|
+
.map((t) => t.trim())
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
: [];
|
|
50
|
+
const hasMultipleEncodings = encodingOptions.length > 1;
|
|
51
|
+
|
|
52
|
+
// Initialize with the first declared content type
|
|
53
|
+
const [selectedEncoding, setSelectedEncoding] = useState<string>(
|
|
54
|
+
encodingOptions[0] ?? ""
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Seed Redux with the first declared encoding on mount so the code snippet
|
|
58
|
+
// reflects a content type immediately, even before the user interacts.
|
|
59
|
+
// The empty dep array is intentional: `fieldEncoding` comes from a static
|
|
60
|
+
// spec value that never changes for the lifetime of this component instance,
|
|
61
|
+
// and re-seeding on every render would fight user selections.
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (encodingOptions[0]) {
|
|
64
|
+
dispatch(
|
|
65
|
+
setFieldEncoding({ field: id, contentType: encodingOptions[0] })
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
}, []);
|
|
70
|
+
const [value, setValue] = useState(() => {
|
|
71
|
+
let initialValue = exampleValue ?? "";
|
|
72
|
+
|
|
73
|
+
if (schemaObject.type === "object" && exampleValue) {
|
|
74
|
+
initialValue = JSON.stringify(exampleValue, null, 2);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return initialValue;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (value) {
|
|
82
|
+
dispatch(setStringFormBody({ key: id, value }));
|
|
83
|
+
} else {
|
|
84
|
+
dispatch(clearFormBodyKey(id));
|
|
85
|
+
}
|
|
86
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
33
89
|
if (
|
|
34
90
|
schemaObject.type === "array" &&
|
|
35
91
|
schemaObject.items?.format === "binary"
|
|
36
92
|
) {
|
|
37
93
|
return (
|
|
38
|
-
|
|
94
|
+
<>
|
|
95
|
+
{label && <FormLabel label={label} required={required} />}
|
|
96
|
+
<FileArrayFormBodyItem id={id} description={schemaObject.description} />
|
|
97
|
+
</>
|
|
39
98
|
);
|
|
40
99
|
}
|
|
41
100
|
|
|
42
101
|
if (schemaObject.format === "binary") {
|
|
43
102
|
return (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
103
|
+
<>
|
|
104
|
+
{label && <FormLabel label={label} required={required} />}
|
|
105
|
+
{hasMultipleEncodings && (
|
|
106
|
+
<div style={{ marginTop: "0.5rem" }}>
|
|
107
|
+
<FormSelect
|
|
108
|
+
label="Content-Type"
|
|
109
|
+
options={encodingOptions}
|
|
110
|
+
value={selectedEncoding}
|
|
111
|
+
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
112
|
+
const ct = e.target.value;
|
|
113
|
+
setSelectedEncoding(ct);
|
|
114
|
+
dispatch(setFieldEncoding({ field: id, contentType: ct }));
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
<FormFileUpload
|
|
120
|
+
placeholder={schemaObject.description || id}
|
|
121
|
+
onChange={(file: any) => {
|
|
122
|
+
if (file === undefined) {
|
|
123
|
+
dispatch(clearFormBodyKey(id));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
dispatch(
|
|
127
|
+
setFileFormBody({
|
|
128
|
+
key: id,
|
|
129
|
+
value: {
|
|
130
|
+
src: `/path/to/${file.name}`,
|
|
131
|
+
content: file,
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
</>
|
|
62
138
|
);
|
|
63
139
|
}
|
|
64
140
|
|
|
65
|
-
if (
|
|
66
|
-
schemaObject.type === "object" &&
|
|
67
|
-
(schemaObject.example || schemaObject.examples)
|
|
68
|
-
) {
|
|
69
|
-
const objectExample = JSON.stringify(
|
|
70
|
-
schemaObject.example ?? schemaObject.examples[0],
|
|
71
|
-
null,
|
|
72
|
-
2
|
|
73
|
-
);
|
|
74
|
-
|
|
141
|
+
if (schemaObject.type === "object") {
|
|
75
142
|
return (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
143
|
+
<>
|
|
144
|
+
{label && <FormLabel label={label} required={required} />}
|
|
145
|
+
<LiveApp
|
|
146
|
+
action={(code: string) =>
|
|
147
|
+
dispatch(setStringFormBody({ key: id, value: code }))
|
|
148
|
+
}
|
|
149
|
+
>
|
|
150
|
+
{value}
|
|
151
|
+
</LiveApp>
|
|
152
|
+
</>
|
|
83
153
|
);
|
|
84
154
|
}
|
|
85
155
|
|
|
@@ -89,9 +159,13 @@ export default function FormBodyItem({
|
|
|
89
159
|
) {
|
|
90
160
|
return (
|
|
91
161
|
<FormSelect
|
|
162
|
+
label={label}
|
|
163
|
+
required={required}
|
|
164
|
+
value={value}
|
|
92
165
|
options={["---", ...schemaObject.enum]}
|
|
93
166
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
94
167
|
const val = e.target.value;
|
|
168
|
+
setValue(val);
|
|
95
169
|
if (val === "---") {
|
|
96
170
|
dispatch(clearFormBodyKey(id));
|
|
97
171
|
} else {
|
|
@@ -109,12 +183,16 @@ export default function FormBodyItem({
|
|
|
109
183
|
// TODO: support all the other types.
|
|
110
184
|
return (
|
|
111
185
|
<FormTextInput
|
|
186
|
+
label={label}
|
|
187
|
+
required={required}
|
|
188
|
+
value={value}
|
|
112
189
|
paramName={id}
|
|
113
190
|
isRequired={
|
|
114
191
|
Array.isArray(schema.required) && schema.required.includes(id)
|
|
115
192
|
}
|
|
116
193
|
placeholder={schemaObject.description || id}
|
|
117
194
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
195
|
+
setValue(e.target.value);
|
|
118
196
|
dispatch(setStringFormBody({ key: id, value: e.target.value }));
|
|
119
197
|
}}
|
|
120
198
|
/>
|
|
@@ -93,6 +93,8 @@ function Body({
|
|
|
93
93
|
const rawSchema = requestBodyMetadata?.content?.[contentType]?.schema;
|
|
94
94
|
const example = requestBodyMetadata?.content?.[contentType]?.example;
|
|
95
95
|
const examples = requestBodyMetadata?.content?.[contentType]?.examples;
|
|
96
|
+
const encoding: Record<string, { contentType?: string }> | undefined =
|
|
97
|
+
requestBodyMetadata?.content?.[contentType]?.encoding;
|
|
96
98
|
|
|
97
99
|
// Resolve the schema based on user's anyOf/oneOf tab selections
|
|
98
100
|
const schema = useMemo(() => {
|
|
@@ -316,23 +318,89 @@ function Body({
|
|
|
316
318
|
) {
|
|
317
319
|
return (
|
|
318
320
|
<FormItem className="openapi-explorer__form-item-body-container">
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
321
|
+
<SchemaTabs className="openapi-tabs__schema" lazy>
|
|
322
|
+
{/* @ts-ignore */}
|
|
323
|
+
<TabItem
|
|
324
|
+
label={translate({
|
|
325
|
+
id: OPENAPI_BODY.EXAMPLE_FROM_SCHEMA,
|
|
326
|
+
message: "Example (from schema)",
|
|
327
|
+
})}
|
|
328
|
+
value="Example (from schema)"
|
|
329
|
+
default
|
|
330
|
+
>
|
|
331
|
+
{Object.entries(schema.properties ?? {}).map(([key, val]: any) => {
|
|
332
|
+
return (
|
|
333
|
+
<FormItem key={key}>
|
|
334
|
+
<FormBodyItem
|
|
335
|
+
schemaObject={val}
|
|
336
|
+
id={key}
|
|
337
|
+
schema={schema}
|
|
338
|
+
exampleValue={val.example}
|
|
339
|
+
label={key}
|
|
340
|
+
required={
|
|
341
|
+
Array.isArray(schema.required) &&
|
|
342
|
+
schema.required.includes(key)
|
|
343
|
+
}
|
|
344
|
+
fieldEncoding={encoding?.[key]?.contentType}
|
|
345
|
+
></FormBodyItem>
|
|
346
|
+
</FormItem>
|
|
347
|
+
);
|
|
348
|
+
})}
|
|
349
|
+
</TabItem>
|
|
350
|
+
{example && (
|
|
351
|
+
// @ts-ignore
|
|
352
|
+
<TabItem label="Example" value="example">
|
|
353
|
+
{Object.entries(schema.properties ?? {}).map(
|
|
354
|
+
([schemaKey, schemaVal]: any) => {
|
|
355
|
+
return (
|
|
356
|
+
<FormItem key={schemaKey}>
|
|
357
|
+
<FormBodyItem
|
|
358
|
+
schemaObject={schemaVal}
|
|
359
|
+
id={schemaKey}
|
|
360
|
+
schema={schema}
|
|
361
|
+
exampleValue={example[schemaKey]}
|
|
362
|
+
label={schemaKey}
|
|
363
|
+
required={
|
|
364
|
+
Array.isArray(schema.required) &&
|
|
365
|
+
schema.required.includes(schemaKey)
|
|
366
|
+
}
|
|
367
|
+
fieldEncoding={encoding?.[schemaKey]?.contentType}
|
|
368
|
+
></FormBodyItem>
|
|
369
|
+
</FormItem>
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
)}
|
|
373
|
+
</TabItem>
|
|
374
|
+
)}
|
|
375
|
+
{examples &&
|
|
376
|
+
Object.entries(examples).map(([key, value]) => {
|
|
377
|
+
return (
|
|
378
|
+
// @ts-ignore
|
|
379
|
+
<TabItem label={key} value={key} key={key}>
|
|
380
|
+
{Object.entries(schema.properties ?? {}).map(
|
|
381
|
+
([schemaKey, schemaVal]: any) => {
|
|
382
|
+
return (
|
|
383
|
+
<FormItem key={schemaKey}>
|
|
384
|
+
<FormBodyItem
|
|
385
|
+
schemaObject={schemaVal}
|
|
386
|
+
id={schemaKey}
|
|
387
|
+
schema={schema}
|
|
388
|
+
exampleValue={value.value?.[schemaKey]}
|
|
389
|
+
label={schemaKey}
|
|
390
|
+
required={
|
|
391
|
+
Array.isArray(schema.required) &&
|
|
392
|
+
schema.required.includes(schemaKey)
|
|
393
|
+
}
|
|
394
|
+
fieldEncoding={encoding?.[schemaKey]?.contentType}
|
|
395
|
+
></FormBodyItem>
|
|
396
|
+
</FormItem>
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
)}
|
|
400
|
+
</TabItem>
|
|
401
|
+
);
|
|
402
|
+
})}
|
|
403
|
+
</SchemaTabs>
|
|
336
404
|
</FormItem>
|
|
337
405
|
);
|
|
338
406
|
}
|
|
@@ -11,6 +11,7 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
|
|
11
11
|
import ApiCodeBlock from "@theme/ApiExplorer/ApiCodeBlock";
|
|
12
12
|
import buildPostmanRequest from "@theme/ApiExplorer/buildPostmanRequest";
|
|
13
13
|
import CodeTabs from "@theme/ApiExplorer/CodeTabs";
|
|
14
|
+
import { useResolvedEncoding } from "@theme/ApiExplorer/EncodingSelection/useResolvedEncoding";
|
|
14
15
|
import { useTypedSelector } from "@theme/ApiItem/hooks";
|
|
15
16
|
import cloneDeep from "lodash/cloneDeep";
|
|
16
17
|
import codegen from "postman-code-generators";
|
|
@@ -30,6 +31,7 @@ export interface Props {
|
|
|
30
31
|
postman: sdk.Request;
|
|
31
32
|
codeSamples: CodeSample[];
|
|
32
33
|
maskCredentials?: boolean;
|
|
34
|
+
requestBody?: import("docusaurus-plugin-openapi-docs/src/openapi/types").RequestBodyObject;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
function CodeTab({ children, hidden, className }: any): React.JSX.Element {
|
|
@@ -44,6 +46,7 @@ function CodeSnippets({
|
|
|
44
46
|
postman,
|
|
45
47
|
codeSamples,
|
|
46
48
|
maskCredentials: propMaskCredentials,
|
|
49
|
+
requestBody,
|
|
47
50
|
}: Props) {
|
|
48
51
|
const { siteConfig } = useDocusaurusContext();
|
|
49
52
|
|
|
@@ -76,7 +79,9 @@ function CodeSnippets({
|
|
|
76
79
|
const authOptions =
|
|
77
80
|
clonedAuth?.options?.[key] ??
|
|
78
81
|
clonedAuth?.options?.[comboAuthId];
|
|
79
|
-
placeholder = authOptions?.find(
|
|
82
|
+
placeholder = authOptions?.find(
|
|
83
|
+
(opt: any) => opt.key === key
|
|
84
|
+
)?.name;
|
|
80
85
|
obj[key] = cleanCredentials(obj[key]);
|
|
81
86
|
} else {
|
|
82
87
|
obj[key] = `<${placeholder ?? key}>`;
|
|
@@ -93,6 +98,8 @@ function CodeSnippets({
|
|
|
93
98
|
})()
|
|
94
99
|
: auth;
|
|
95
100
|
|
|
101
|
+
const encoding = useResolvedEncoding(requestBody);
|
|
102
|
+
|
|
96
103
|
// Create a Postman request object using cleanedAuth or original auth
|
|
97
104
|
const cleanedPostmanRequest = buildPostmanRequest(postman, {
|
|
98
105
|
queryParams,
|
|
@@ -104,6 +111,7 @@ function CodeSnippets({
|
|
|
104
111
|
body,
|
|
105
112
|
server,
|
|
106
113
|
auth: cleanedAuth,
|
|
114
|
+
encoding,
|
|
107
115
|
});
|
|
108
116
|
|
|
109
117
|
// User-defined languages array
|
|
@@ -9,11 +9,12 @@ import React, { cloneElement, ReactElement, useEffect, useRef } from "react";
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
sanitizeTabsChildren,
|
|
12
|
+
type TabItemProps,
|
|
12
13
|
type TabProps,
|
|
14
|
+
TabsProvider,
|
|
13
15
|
useScrollPositionBlocker,
|
|
14
|
-
|
|
16
|
+
useTabsContextValue,
|
|
15
17
|
} from "@docusaurus/theme-common/internal";
|
|
16
|
-
import { TabItemProps } from "@docusaurus/theme-common/lib/utils/tabsUtils";
|
|
17
18
|
import useIsBrowser from "@docusaurus/useIsBrowser";
|
|
18
19
|
import clsx from "clsx";
|
|
19
20
|
|
|
@@ -43,7 +44,7 @@ function TabList({
|
|
|
43
44
|
selectedValue,
|
|
44
45
|
selectValue,
|
|
45
46
|
tabValues,
|
|
46
|
-
}: CodeTabsProps & ReturnType<typeof
|
|
47
|
+
}: CodeTabsProps & ReturnType<typeof useTabsContextValue>) {
|
|
47
48
|
const tabRefs = useRef<(HTMLLIElement | null)[]>([]);
|
|
48
49
|
const tabsScrollContainerRef = useRef<any>(null);
|
|
49
50
|
const { blockElementScrollPositionUntilNextRender } =
|
|
@@ -192,7 +193,8 @@ function TabContent({
|
|
|
192
193
|
lazy,
|
|
193
194
|
children,
|
|
194
195
|
selectedValue,
|
|
195
|
-
}: CodeTabsProps &
|
|
196
|
+
}: CodeTabsProps &
|
|
197
|
+
ReturnType<typeof useTabsContextValue>): React.JSX.Element | null {
|
|
196
198
|
const childTabs = (Array.isArray(children) ? children : [children]).filter(
|
|
197
199
|
Boolean
|
|
198
200
|
) as ReactElement<TabItemProps>[];
|
|
@@ -207,28 +209,26 @@ function TabContent({
|
|
|
207
209
|
return cloneElement(selectedTabItem, { className: "margin-top--md" });
|
|
208
210
|
}
|
|
209
211
|
return (
|
|
210
|
-
<div className="margin-top--md openapi-tabs__code-content">
|
|
211
|
-
{childTabs.map((tabItem, i) =>
|
|
212
|
-
cloneElement(tabItem, {
|
|
213
|
-
key: i,
|
|
214
|
-
hidden: tabItem.props.value !== selectedValue,
|
|
215
|
-
})
|
|
216
|
-
)}
|
|
217
|
-
</div>
|
|
212
|
+
<div className="margin-top--md openapi-tabs__code-content">{childTabs}</div>
|
|
218
213
|
);
|
|
219
214
|
}
|
|
220
215
|
|
|
221
216
|
function TabsComponent(props: CodeTabsProps & Props): React.JSX.Element {
|
|
222
|
-
const tabs =
|
|
217
|
+
const tabs = useTabsContextValue(props);
|
|
223
218
|
const { className } = props;
|
|
224
219
|
|
|
225
220
|
return (
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
221
|
+
<TabsProvider value={tabs}>
|
|
222
|
+
<div
|
|
223
|
+
className={clsx(
|
|
224
|
+
"tabs-container openapi-tabs__code-container",
|
|
225
|
+
className
|
|
226
|
+
)}
|
|
227
|
+
>
|
|
228
|
+
<TabList {...props} {...tabs} />
|
|
229
|
+
<TabContent {...props} {...tabs} />
|
|
230
|
+
</div>
|
|
231
|
+
</TabsProvider>
|
|
232
232
|
);
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -12,6 +12,7 @@ import FormSelect from "@theme/ApiExplorer/FormSelect";
|
|
|
12
12
|
import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks";
|
|
13
13
|
|
|
14
14
|
import { setContentType } from "./slice";
|
|
15
|
+
import { clearEncodingSelection } from "@theme/ApiExplorer/EncodingSelection/slice";
|
|
15
16
|
|
|
16
17
|
function ContentType() {
|
|
17
18
|
const value = useTypedSelector((state: any) => state.contentType.value);
|
|
@@ -23,13 +24,15 @@ function ContentType() {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
return (
|
|
26
|
-
<FormItem
|
|
27
|
+
<FormItem>
|
|
27
28
|
<FormSelect
|
|
29
|
+
label="Content-Type"
|
|
28
30
|
value={value}
|
|
29
31
|
options={options}
|
|
30
|
-
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
|
|
31
|
-
dispatch(setContentType(e.target.value))
|
|
32
|
-
|
|
32
|
+
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
33
|
+
dispatch(setContentType(e.target.value));
|
|
34
|
+
dispatch(clearEncodingSelection());
|
|
35
|
+
}}
|
|
33
36
|
/>
|
|
34
37
|
</FormItem>
|
|
35
38
|
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
9
|
+
|
|
10
|
+
// Maps form field name → user-selected content type
|
|
11
|
+
export type State = Record<string, string>;
|
|
12
|
+
|
|
13
|
+
const initialState: State = {};
|
|
14
|
+
|
|
15
|
+
export const slice = createSlice({
|
|
16
|
+
name: "encodingSelection",
|
|
17
|
+
initialState,
|
|
18
|
+
reducers: {
|
|
19
|
+
setFieldEncoding: (
|
|
20
|
+
state,
|
|
21
|
+
action: PayloadAction<{ field: string; contentType: string }>
|
|
22
|
+
) => {
|
|
23
|
+
state[action.payload.field] = action.payload.contentType;
|
|
24
|
+
},
|
|
25
|
+
clearEncodingSelection: () => initialState,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const { setFieldEncoding, clearEncodingSelection } = slice.actions;
|
|
30
|
+
|
|
31
|
+
export default slice.reducer;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { useTypedSelector } from "@theme/ApiItem/hooks";
|
|
9
|
+
import type { RequestBodyObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Merges the spec-declared `encoding` for the active content type with any
|
|
13
|
+
* per-field content-type selections the user has made in the UI. User picks
|
|
14
|
+
* take precedence over the spec default.
|
|
15
|
+
*
|
|
16
|
+
* Returns `undefined` when no encoding is declared for the current content
|
|
17
|
+
* type so callers can skip the encoding path entirely.
|
|
18
|
+
*/
|
|
19
|
+
export function useResolvedEncoding(
|
|
20
|
+
requestBody: RequestBodyObject | undefined
|
|
21
|
+
): Record<string, { contentType?: string }> | undefined {
|
|
22
|
+
const contentType = useTypedSelector((state: any) => state.contentType.value);
|
|
23
|
+
const encodingSelection = useTypedSelector(
|
|
24
|
+
(state: any) => state.encodingSelection
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const specEncoding: Record<string, { contentType?: string }> =
|
|
28
|
+
requestBody?.content?.[contentType]?.encoding ?? {};
|
|
29
|
+
|
|
30
|
+
if (!Object.keys(specEncoding).length) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return Object.fromEntries(
|
|
35
|
+
Object.entries(specEncoding).map(([field, enc]) => [
|
|
36
|
+
field,
|
|
37
|
+
{
|
|
38
|
+
...enc,
|
|
39
|
+
contentType: encodingSelection[field] ?? enc.contentType,
|
|
40
|
+
},
|
|
41
|
+
])
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -7,31 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
import React from "react";
|
|
9
9
|
|
|
10
|
-
import { translate } from "@docusaurus/Translate";
|
|
11
|
-
import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
|
|
12
10
|
import clsx from "clsx";
|
|
13
11
|
|
|
14
12
|
export interface Props {
|
|
15
|
-
label?: string;
|
|
16
|
-
type?: string;
|
|
17
|
-
required?: boolean | undefined;
|
|
18
13
|
children?: React.ReactNode;
|
|
19
14
|
className?: string;
|
|
20
15
|
}
|
|
21
16
|
|
|
22
|
-
function FormItem({
|
|
17
|
+
function FormItem({ children, className }: Props) {
|
|
23
18
|
return (
|
|
24
19
|
<div className={clsx("openapi-explorer__form-item", className)}>
|
|
25
|
-
{
|
|
26
|
-
<label className="openapi-explorer__form-item-label">{label}</label>
|
|
27
|
-
)}
|
|
28
|
-
{type && <span style={{ opacity: 0.6 }}> — {type}</span>}
|
|
29
|
-
{required && (
|
|
30
|
-
<span className="openapi-schema__required">
|
|
31
|
-
{translate({ id: OPENAPI_SCHEMA_ITEM.REQUIRED, message: "required" })}
|
|
32
|
-
</span>
|
|
33
|
-
)}
|
|
34
|
-
<div>{children}</div>
|
|
20
|
+
{children}
|
|
35
21
|
</div>
|
|
36
22
|
);
|
|
37
23
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
|
|
10
|
+
import { translate } from "@docusaurus/Translate";
|
|
11
|
+
import { OPENAPI_SCHEMA_ITEM } from "@theme/translationIds";
|
|
12
|
+
|
|
13
|
+
export interface Props {
|
|
14
|
+
htmlFor?: string;
|
|
15
|
+
label: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function FormLabel({ htmlFor, label, type, required }: Props) {
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
{htmlFor ? (
|
|
24
|
+
<label className="openapi-explorer__form-item-label" htmlFor={htmlFor}>
|
|
25
|
+
{label}
|
|
26
|
+
</label>
|
|
27
|
+
) : (
|
|
28
|
+
<span className="openapi-explorer__form-item-label">{label}</span>
|
|
29
|
+
)}
|
|
30
|
+
{type && <span style={{ opacity: 0.6 }}> — {type}</span>}
|
|
31
|
+
{required && (
|
|
32
|
+
<span className="openapi-schema__required">
|
|
33
|
+
{translate({
|
|
34
|
+
id: OPENAPI_SCHEMA_ITEM.REQUIRED,
|
|
35
|
+
message: "required",
|
|
36
|
+
})}
|
|
37
|
+
</span>
|
|
38
|
+
)}
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default FormLabel;
|