docusaurus-theme-openapi-docs 4.7.0 → 5.0.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/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/Authorization/index.js +12 -18
- package/lib/theme/ApiExplorer/Authorization/slice.d.ts +1 -1
- package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +0 -4
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +6 -2
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +191 -38
- package/lib/theme/ApiExplorer/Body/index.d.ts +1 -1
- package/lib/theme/ApiExplorer/Body/index.js +86 -15
- package/lib/theme/ApiExplorer/Body/resolveSchemaWithSelections.d.ts +1 -1
- 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/ParamOptions/slice.d.ts +1 -1
- package/lib/theme/ApiExplorer/Request/_Request.scss +11 -0
- package/lib/theme/ApiExplorer/Request/index.d.ts +1 -1
- 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.d.ts +1 -1
- package/lib/theme/ApiExplorer/Response/index.js +98 -12
- package/lib/theme/ApiExplorer/SecuritySchemes/index.js +2 -2
- package/lib/theme/ApiExplorer/Server/index.d.ts +4 -1
- package/lib/theme/ApiExplorer/Server/index.js +6 -3
- package/lib/theme/ApiExplorer/Server/slice.d.ts +1 -1
- package/lib/theme/ApiExplorer/buildPostmanRequest.d.ts +5 -2
- package/lib/theme/ApiExplorer/buildPostmanRequest.js +46 -5
- package/lib/theme/ApiExplorer/index.d.ts +1 -1
- 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/ParamsDetails/index.js +2 -2
- package/lib/theme/ParamsItem/index.js +27 -0
- package/lib/theme/RequestSchema/index.d.ts +1 -1
- package/lib/theme/RequestSchema/index.js +174 -111
- package/lib/theme/ResponseHeaders/index.js +0 -1
- package/lib/theme/ResponseSchema/index.d.ts +1 -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/StatusCodes/index.d.ts +1 -1
- 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/Authorization/index.tsx +27 -33
- package/src/theme/ApiExplorer/Authorization/slice.ts +1 -1
- package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +2 -5
- package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +119 -39
- package/src/theme/ApiExplorer/Body/index.tsx +88 -21
- package/src/theme/ApiExplorer/Body/resolveSchemaWithSelections.ts +1 -1
- 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 -17
- 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/ParamOptions/slice.ts +1 -1
- package/src/theme/ApiExplorer/Request/_Request.scss +11 -0
- package/src/theme/ApiExplorer/Request/index.tsx +22 -10
- 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 +37 -17
- package/src/theme/ApiExplorer/SecuritySchemes/index.tsx +2 -3
- package/src/theme/ApiExplorer/Server/index.tsx +10 -3
- package/src/theme/ApiExplorer/Server/slice.ts +1 -1
- package/src/theme/ApiExplorer/buildPostmanRequest.ts +53 -6
- package/src/theme/ApiExplorer/index.tsx +2 -1
- package/src/theme/ApiItem/index.tsx +3 -2
- 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/ParamsDetails/index.tsx +2 -3
- package/src/theme/ParamsItem/index.tsx +25 -0
- package/src/theme/RequestSchema/index.tsx +144 -87
- package/src/theme/ResponseHeaders/index.tsx +1 -2
- package/src/theme/ResponseSchema/index.tsx +1 -1
- 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/StatusCodes/index.tsx +1 -1
- 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 +15 -52
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
-
import React, { useState } from "react";
|
|
8
|
+
import React, { useState, useId } from "react";
|
|
9
9
|
|
|
10
10
|
import { translate } from "@docusaurus/Translate";
|
|
11
11
|
import FormItem from "@theme/ApiExplorer/FormItem";
|
|
@@ -19,36 +19,117 @@ import { OPENAPI_PARAM_OPTIONS } from "@theme/translationIds";
|
|
|
19
19
|
|
|
20
20
|
import { Param } from "./slice";
|
|
21
21
|
|
|
22
|
+
export interface LabelProps {
|
|
23
|
+
label?: string;
|
|
24
|
+
type?: string;
|
|
25
|
+
required?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
export interface ParamProps {
|
|
23
29
|
param: Param;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Extracts enum values from a schema, including when wrapped in allOf.
|
|
34
|
+
* This handles cases where an enum is referenced via allOf for composition.
|
|
35
|
+
*/
|
|
36
|
+
export function getSchemaEnum(schema: any): any[] | undefined {
|
|
37
|
+
// Direct enum on schema
|
|
38
|
+
if (schema?.enum) {
|
|
39
|
+
return schema.enum;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Enum inside allOf - check each item
|
|
43
|
+
if (schema?.allOf && Array.isArray(schema.allOf)) {
|
|
44
|
+
for (const item of schema.allOf) {
|
|
45
|
+
if (item.enum) {
|
|
46
|
+
return item.enum;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// const is semantically a single-value enum
|
|
52
|
+
if (schema?.const !== undefined) {
|
|
53
|
+
return [schema.const];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ParamOption({
|
|
60
|
+
param,
|
|
61
|
+
label,
|
|
62
|
+
type,
|
|
63
|
+
required,
|
|
64
|
+
}: ParamProps & LabelProps) {
|
|
65
|
+
const schemaEnum = getSchemaEnum(param.schema);
|
|
66
|
+
const itemsEnum = getSchemaEnum(param.schema?.items);
|
|
67
|
+
|
|
68
|
+
if (param.schema?.type === "array" && itemsEnum) {
|
|
69
|
+
return (
|
|
70
|
+
<ParamMultiSelectFormItem
|
|
71
|
+
param={param}
|
|
72
|
+
label={label}
|
|
73
|
+
type={type}
|
|
74
|
+
required={required}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
29
77
|
}
|
|
30
78
|
|
|
31
79
|
if (param.schema?.type === "array") {
|
|
32
|
-
return
|
|
80
|
+
return (
|
|
81
|
+
<ParamArrayFormItem
|
|
82
|
+
param={param}
|
|
83
|
+
label={label}
|
|
84
|
+
type={type}
|
|
85
|
+
required={required}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
33
88
|
}
|
|
34
89
|
|
|
35
|
-
if (
|
|
36
|
-
return
|
|
90
|
+
if (schemaEnum) {
|
|
91
|
+
return (
|
|
92
|
+
<ParamSelectFormItem
|
|
93
|
+
param={param}
|
|
94
|
+
label={label}
|
|
95
|
+
type={type}
|
|
96
|
+
required={required}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
37
99
|
}
|
|
38
100
|
|
|
39
101
|
if (param.schema?.type === "boolean") {
|
|
40
|
-
return
|
|
102
|
+
return (
|
|
103
|
+
<ParamBooleanFormItem
|
|
104
|
+
param={param}
|
|
105
|
+
label={label}
|
|
106
|
+
type={type}
|
|
107
|
+
required={required}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
41
110
|
}
|
|
42
111
|
|
|
43
112
|
// integer, number, string, int32, int64, float, double, object, byte, binary,
|
|
44
113
|
// date-time, date, password
|
|
45
|
-
return
|
|
114
|
+
return (
|
|
115
|
+
<ParamTextFormItem
|
|
116
|
+
param={param}
|
|
117
|
+
label={label}
|
|
118
|
+
type={type}
|
|
119
|
+
required={required}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
46
122
|
}
|
|
47
123
|
|
|
48
124
|
function ParamOptionWrapper({ param }: ParamProps) {
|
|
49
125
|
return (
|
|
50
|
-
<FormItem
|
|
51
|
-
<ParamOption
|
|
126
|
+
<FormItem>
|
|
127
|
+
<ParamOption
|
|
128
|
+
param={param}
|
|
129
|
+
label={param.name}
|
|
130
|
+
type={param.in}
|
|
131
|
+
required={param.required}
|
|
132
|
+
/>
|
|
52
133
|
</FormItem>
|
|
53
134
|
);
|
|
54
135
|
}
|
|
@@ -56,6 +137,8 @@ function ParamOptionWrapper({ param }: ParamProps) {
|
|
|
56
137
|
function ParamOptions() {
|
|
57
138
|
const [showOptional, setShowOptional] = useState(false);
|
|
58
139
|
|
|
140
|
+
const optionalId = useId();
|
|
141
|
+
|
|
59
142
|
const pathParams = useTypedSelector((state: any) => state.params.path);
|
|
60
143
|
const queryParams = useTypedSelector((state: any) => state.params.query);
|
|
61
144
|
const cookieParams = useTypedSelector((state: any) => state.params.cookie);
|
|
@@ -84,6 +167,8 @@ function ParamOptions() {
|
|
|
84
167
|
<button
|
|
85
168
|
type="button"
|
|
86
169
|
className="openapi-explorer__show-more-btn"
|
|
170
|
+
aria-expanded={showOptional}
|
|
171
|
+
aria-controls={optionalId}
|
|
87
172
|
onClick={() => setShowOptional((prev) => !prev)}
|
|
88
173
|
>
|
|
89
174
|
<span
|
|
@@ -137,6 +222,7 @@ function ParamOptions() {
|
|
|
137
222
|
? "openapi-explorer__show-options"
|
|
138
223
|
: "openapi-explorer__hide-options"
|
|
139
224
|
}
|
|
225
|
+
id={optionalId}
|
|
140
226
|
>
|
|
141
227
|
{optionalParams.map((param) => (
|
|
142
228
|
<ParamOptionWrapper
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
9
|
-
import { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
9
|
+
import type { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
10
10
|
|
|
11
11
|
export type Param = ParameterObject & { value?: string[] | string };
|
|
12
12
|
|
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.openapi-explorer__expand-details-btn {
|
|
51
|
+
-webkit-appearance: none;
|
|
52
|
+
-moz-appearance: none;
|
|
53
|
+
appearance: none;
|
|
54
|
+
padding: 0;
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
border: 0px solid transparent;
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
text-transform: inherit;
|
|
59
|
+
font-weight: inherit;
|
|
60
|
+
font-size: inherit;
|
|
61
|
+
|
|
51
62
|
&:hover {
|
|
52
63
|
cursor: pointer;
|
|
53
64
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
// @ts-nocheck
|
|
9
|
-
import React, { useState } from "react";
|
|
9
|
+
import React, { useState, useId } from "react";
|
|
10
10
|
|
|
11
11
|
import { useDoc } from "@docusaurus/plugin-content-docs/client";
|
|
12
12
|
import { translate } from "@docusaurus/Translate";
|
|
@@ -25,10 +25,11 @@ import {
|
|
|
25
25
|
clearHeaders,
|
|
26
26
|
} from "@theme/ApiExplorer/Response/slice";
|
|
27
27
|
import Server from "@theme/ApiExplorer/Server";
|
|
28
|
+
import { useResolvedEncoding } from "@theme/ApiExplorer/EncodingSelection/useResolvedEncoding";
|
|
28
29
|
import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks";
|
|
29
30
|
import { OPENAPI_REQUEST } from "@theme/translationIds";
|
|
30
|
-
import { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
31
|
-
import { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
31
|
+
import type { ParameterObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
32
|
+
import type { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
32
33
|
import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
|
|
33
34
|
import * as sdk from "postman-collection";
|
|
34
35
|
import { FormProvider, useForm } from "react-hook-form";
|
|
@@ -43,6 +44,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
43
44
|
const { siteConfig } = useDocusaurusContext();
|
|
44
45
|
const themeConfig = siteConfig.themeConfig as ThemeConfig;
|
|
45
46
|
const requestTimeout = themeConfig.api?.requestTimeout;
|
|
47
|
+
const requestCredentials = themeConfig.api?.requestCredentials;
|
|
46
48
|
// Frontmatter proxy (per-spec) takes precedence over theme config proxy (site-wide)
|
|
47
49
|
const proxy = frontMatterProxy ?? themeConfig.api?.proxy;
|
|
48
50
|
|
|
@@ -66,6 +68,8 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
66
68
|
const [expandParams, setExpandParams] = useState(true);
|
|
67
69
|
const [expandServer, setExpandServer] = useState(true);
|
|
68
70
|
|
|
71
|
+
const serverLabelId = useId();
|
|
72
|
+
|
|
69
73
|
const allParams = [
|
|
70
74
|
...pathParams,
|
|
71
75
|
...queryParams,
|
|
@@ -73,6 +77,8 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
73
77
|
...headerParams,
|
|
74
78
|
];
|
|
75
79
|
|
|
80
|
+
const encoding = useResolvedEncoding(item.requestBody);
|
|
81
|
+
|
|
76
82
|
const postmanRequest = buildPostmanRequest(postman, {
|
|
77
83
|
queryParams,
|
|
78
84
|
pathParams,
|
|
@@ -83,6 +89,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
83
89
|
body,
|
|
84
90
|
server,
|
|
85
91
|
auth,
|
|
92
|
+
encoding,
|
|
86
93
|
});
|
|
87
94
|
|
|
88
95
|
const delay = (ms: number) =>
|
|
@@ -99,7 +106,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
99
106
|
(param: { in: "path" | "query" | "header" | "cookie" }) => {
|
|
100
107
|
const paramType = param.in;
|
|
101
108
|
const paramsArray: ParameterObject[] = paramsObject[paramType];
|
|
102
|
-
paramsArray
|
|
109
|
+
paramsArray?.push(param as ParameterObject);
|
|
103
110
|
}
|
|
104
111
|
);
|
|
105
112
|
|
|
@@ -171,7 +178,9 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
171
178
|
postmanRequest,
|
|
172
179
|
proxy,
|
|
173
180
|
body,
|
|
174
|
-
requestTimeout
|
|
181
|
+
requestTimeout,
|
|
182
|
+
requestCredentials,
|
|
183
|
+
encoding
|
|
175
184
|
);
|
|
176
185
|
if (res.headers.get("content-type")?.includes("text/event-stream")) {
|
|
177
186
|
await handleEventStream(res);
|
|
@@ -249,7 +258,8 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
249
258
|
})}
|
|
250
259
|
</span>
|
|
251
260
|
{allDetailsExpanded ? (
|
|
252
|
-
<
|
|
261
|
+
<button
|
|
262
|
+
type="button"
|
|
253
263
|
className="openapi-explorer__expand-details-btn"
|
|
254
264
|
onClick={collapseAllDetails}
|
|
255
265
|
>
|
|
@@ -257,9 +267,10 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
257
267
|
id: OPENAPI_REQUEST.COLLAPSE_ALL,
|
|
258
268
|
message: "Collapse all",
|
|
259
269
|
})}
|
|
260
|
-
</
|
|
270
|
+
</button>
|
|
261
271
|
) : (
|
|
262
|
-
<
|
|
272
|
+
<button
|
|
273
|
+
type="button"
|
|
263
274
|
className="openapi-explorer__expand-details-btn"
|
|
264
275
|
onClick={expandAllDetails}
|
|
265
276
|
>
|
|
@@ -267,7 +278,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
267
278
|
id: OPENAPI_REQUEST.EXPAND_ALL,
|
|
268
279
|
message: "Expand all",
|
|
269
280
|
})}
|
|
270
|
-
</
|
|
281
|
+
</button>
|
|
271
282
|
)}
|
|
272
283
|
</div>
|
|
273
284
|
<div className="openapi-explorer__details-outer-container">
|
|
@@ -277,6 +288,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
277
288
|
className="openapi-explorer__details-container"
|
|
278
289
|
>
|
|
279
290
|
<summary
|
|
291
|
+
id={serverLabelId}
|
|
280
292
|
className="openapi-explorer__details-summary"
|
|
281
293
|
onClick={(e) => {
|
|
282
294
|
e.preventDefault();
|
|
@@ -288,7 +300,7 @@ function Request({ item }: { item: ApiItem }) {
|
|
|
288
300
|
message: "Base URL",
|
|
289
301
|
})}
|
|
290
302
|
</summary>
|
|
291
|
-
<Server />
|
|
303
|
+
<Server labelId={serverLabelId} />
|
|
292
304
|
</details>
|
|
293
305
|
)}
|
|
294
306
|
{showAuth && (
|
|
@@ -114,7 +114,9 @@ async function makeRequest(
|
|
|
114
114
|
request: sdk.Request,
|
|
115
115
|
proxy: string | undefined,
|
|
116
116
|
_body: Body,
|
|
117
|
-
timeout: number = DEFAULT_REQUEST_TIMEOUT
|
|
117
|
+
timeout: number = DEFAULT_REQUEST_TIMEOUT,
|
|
118
|
+
credentials?: RequestCredentials,
|
|
119
|
+
encoding?: Record<string, { contentType?: string }>
|
|
118
120
|
) {
|
|
119
121
|
const headers = request.toJSON().header;
|
|
120
122
|
|
|
@@ -226,12 +228,25 @@ async function makeRequest(
|
|
|
226
228
|
const members = (request.body as any)?.formdata?.members;
|
|
227
229
|
if (Array.isArray(members)) {
|
|
228
230
|
for (const data of members) {
|
|
231
|
+
const partContentType = encoding?.[data.key]?.contentType
|
|
232
|
+
?.split(",")[0]
|
|
233
|
+
.trim();
|
|
229
234
|
if (data.key && data.value.content) {
|
|
230
|
-
|
|
235
|
+
const blob = partContentType
|
|
236
|
+
? new Blob([data.value.content], { type: partContentType })
|
|
237
|
+
: data.value.content;
|
|
238
|
+
myBody.append(data.key, blob);
|
|
231
239
|
}
|
|
232
240
|
// handle generic key-value payload
|
|
233
241
|
if (data.key && typeof data.value === "string") {
|
|
234
|
-
|
|
242
|
+
if (partContentType) {
|
|
243
|
+
myBody.append(
|
|
244
|
+
data.key,
|
|
245
|
+
new Blob([data.value], { type: partContentType })
|
|
246
|
+
);
|
|
247
|
+
} else {
|
|
248
|
+
myBody.append(data.key, data.value);
|
|
249
|
+
}
|
|
235
250
|
}
|
|
236
251
|
}
|
|
237
252
|
}
|
|
@@ -252,6 +267,7 @@ async function makeRequest(
|
|
|
252
267
|
method: request.method,
|
|
253
268
|
headers: myHeaders,
|
|
254
269
|
body: myBody,
|
|
270
|
+
...(credentials && { credentials }),
|
|
255
271
|
};
|
|
256
272
|
|
|
257
273
|
let finalUrl = request.url.toString();
|
|
@@ -43,6 +43,17 @@
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
.openapi-explorer__response-clear-btn {
|
|
46
|
+
-webkit-appearance: none;
|
|
47
|
+
-moz-appearance: none;
|
|
48
|
+
appearance: none;
|
|
49
|
+
padding: 0;
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
border: 0px solid transparent;
|
|
52
|
+
background-color: transparent;
|
|
53
|
+
text-transform: inherit;
|
|
54
|
+
font-weight: inherit;
|
|
55
|
+
font-size: inherit;
|
|
56
|
+
|
|
46
57
|
&:hover {
|
|
47
58
|
cursor: pointer;
|
|
48
59
|
}
|
|
@@ -9,15 +9,15 @@ import React from "react";
|
|
|
9
9
|
|
|
10
10
|
import { useDoc } from "@docusaurus/plugin-content-docs/client";
|
|
11
11
|
import { usePrismTheme } from "@docusaurus/theme-common";
|
|
12
|
-
import { translate } from "@docusaurus/Translate";
|
|
12
|
+
import Translate, { translate } from "@docusaurus/Translate";
|
|
13
13
|
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
|
14
14
|
import ApiCodeBlock from "@theme/ApiExplorer/ApiCodeBlock";
|
|
15
15
|
import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks";
|
|
16
16
|
import SchemaTabs from "@theme/SchemaTabs";
|
|
17
17
|
import TabItem from "@theme/TabItem";
|
|
18
|
-
import { OPENAPI_RESPONSE } from "@theme/translationIds";
|
|
18
|
+
import { OPENAPI_REQUEST, OPENAPI_RESPONSE } from "@theme/translationIds";
|
|
19
19
|
import clsx from "clsx";
|
|
20
|
-
import { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
20
|
+
import type { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
21
21
|
import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
|
|
22
22
|
|
|
23
23
|
import { clearResponse, clearCode, clearHeaders } from "./slice";
|
|
@@ -47,8 +47,7 @@ function Response({ item }: { item: ApiItem }) {
|
|
|
47
47
|
const { siteConfig } = useDocusaurusContext();
|
|
48
48
|
const themeConfig = siteConfig.themeConfig as ThemeConfig;
|
|
49
49
|
const hideSendButton = metadata.frontMatter.hide_send_button;
|
|
50
|
-
const proxy =
|
|
51
|
-
metadata.frontMatter.proxy ?? themeConfig.api?.proxy;
|
|
50
|
+
const proxy = metadata.frontMatter.proxy ?? themeConfig.api?.proxy;
|
|
52
51
|
const prismTheme = usePrismTheme();
|
|
53
52
|
const code = useTypedSelector((state: any) => state.response.code);
|
|
54
53
|
const headers = useTypedSelector((state: any) => state.response.headers);
|
|
@@ -85,7 +84,8 @@ function Response({ item }: { item: ApiItem }) {
|
|
|
85
84
|
<span className="openapi-explorer__response-title">
|
|
86
85
|
{translate({ id: OPENAPI_RESPONSE.TITLE, message: "Response" })}
|
|
87
86
|
</span>
|
|
88
|
-
<
|
|
87
|
+
<button
|
|
88
|
+
type="button"
|
|
89
89
|
className="openapi-explorer__response-clear-btn"
|
|
90
90
|
onClick={() => {
|
|
91
91
|
dispatch(clearResponse());
|
|
@@ -94,7 +94,7 @@ function Response({ item }: { item: ApiItem }) {
|
|
|
94
94
|
}}
|
|
95
95
|
>
|
|
96
96
|
{translate({ id: OPENAPI_RESPONSE.CLEAR, message: "Clear" })}
|
|
97
|
-
</
|
|
97
|
+
</button>
|
|
98
98
|
</div>
|
|
99
99
|
<div
|
|
100
100
|
style={{
|
|
@@ -127,11 +127,22 @@ function Response({ item }: { item: ApiItem }) {
|
|
|
127
127
|
>
|
|
128
128
|
{prettyResponse || (
|
|
129
129
|
<p className="openapi-explorer__response-placeholder-message">
|
|
130
|
-
|
|
131
|
-
id
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
<Translate
|
|
131
|
+
id={OPENAPI_RESPONSE.PLACEHOLDER}
|
|
132
|
+
values={{
|
|
133
|
+
code: (
|
|
134
|
+
<code>
|
|
135
|
+
<Translate id={OPENAPI_REQUEST.SEND_BUTTON}>
|
|
136
|
+
Send API Request
|
|
137
|
+
</Translate>
|
|
138
|
+
</code>
|
|
139
|
+
),
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
{
|
|
143
|
+
"Click the {code} button above and see the response here!"
|
|
144
|
+
}
|
|
145
|
+
</Translate>
|
|
135
146
|
</p>
|
|
136
147
|
)}
|
|
137
148
|
</ApiCodeBlock>
|
|
@@ -164,11 +175,20 @@ function Response({ item }: { item: ApiItem }) {
|
|
|
164
175
|
</div>
|
|
165
176
|
) : (
|
|
166
177
|
<p className="openapi-explorer__response-placeholder-message">
|
|
167
|
-
|
|
168
|
-
id
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
<Translate
|
|
179
|
+
id={OPENAPI_RESPONSE.PLACEHOLDER}
|
|
180
|
+
values={{
|
|
181
|
+
code: (
|
|
182
|
+
<code>
|
|
183
|
+
<Translate id={OPENAPI_REQUEST.SEND_BUTTON}>
|
|
184
|
+
Send API Request
|
|
185
|
+
</Translate>
|
|
186
|
+
</code>
|
|
187
|
+
),
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
{"Click the {code} button above and see the response here!"}
|
|
191
|
+
</Translate>
|
|
172
192
|
</p>
|
|
173
193
|
)}
|
|
174
194
|
</div>
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import React from "react";
|
|
9
9
|
|
|
10
|
-
import { translate } from "@docusaurus/Translate";
|
|
11
|
-
import { OPENAPI_SECURITY_SCHEMES } from "@theme/translationIds";
|
|
12
|
-
|
|
13
10
|
import Link from "@docusaurus/Link";
|
|
11
|
+
import { translate } from "@docusaurus/Translate";
|
|
14
12
|
import { useTypedSelector } from "@theme/ApiItem/hooks";
|
|
13
|
+
import { OPENAPI_SECURITY_SCHEMES } from "@theme/translationIds";
|
|
15
14
|
|
|
16
15
|
function SecuritySchemes(props: any) {
|
|
17
16
|
const options = useTypedSelector((state: any) => state.auth.options);
|
|
@@ -17,7 +17,11 @@ import { OPENAPI_SERVER } from "@theme/translationIds";
|
|
|
17
17
|
|
|
18
18
|
import { setServer, setServerVariable } from "./slice";
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
interface ServerProps {
|
|
21
|
+
labelId?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Server({ labelId }: ServerProps) {
|
|
21
25
|
const [isEditing, setIsEditing] = useState(false);
|
|
22
26
|
const value = useTypedSelector((state: any) => state.server.value);
|
|
23
27
|
const options = useTypedSelector((state: any) => state.server.options);
|
|
@@ -79,6 +83,7 @@ function Server() {
|
|
|
79
83
|
>
|
|
80
84
|
<FormItem>
|
|
81
85
|
<FormSelect
|
|
86
|
+
ariaLabelledBy={labelId}
|
|
82
87
|
options={options.map((s: any) => s.url)}
|
|
83
88
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
84
89
|
dispatch(
|
|
@@ -99,8 +104,9 @@ function Server() {
|
|
|
99
104
|
Object.keys(value.variables).map((key) => {
|
|
100
105
|
if (value.variables?.[key].enum !== undefined) {
|
|
101
106
|
return (
|
|
102
|
-
<FormItem
|
|
107
|
+
<FormItem>
|
|
103
108
|
<FormSelect
|
|
109
|
+
label={key}
|
|
104
110
|
options={value.variables[key].enum}
|
|
105
111
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
106
112
|
dispatch(
|
|
@@ -115,8 +121,9 @@ function Server() {
|
|
|
115
121
|
);
|
|
116
122
|
}
|
|
117
123
|
return (
|
|
118
|
-
<FormItem
|
|
124
|
+
<FormItem>
|
|
119
125
|
<FormTextInput
|
|
126
|
+
label={key}
|
|
120
127
|
placeholder={value.variables?.[key].default}
|
|
121
128
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
122
129
|
dispatch(
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
9
|
-
import { ServerObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
9
|
+
import type { ServerObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
10
10
|
// TODO: we might want to export this
|
|
11
11
|
|
|
12
12
|
export interface State {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { AuthState, Scheme } from "@theme/ApiExplorer/Authorization/slice";
|
|
9
9
|
import { Body, Content } from "@theme/ApiExplorer/Body/slice";
|
|
10
|
-
import {
|
|
10
|
+
import type {
|
|
11
11
|
ParameterObject,
|
|
12
12
|
ServerObject,
|
|
13
13
|
} from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
@@ -293,12 +293,36 @@ function tryDecodeJsonParam(value: string): any {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// TODO: this is all a bit hacky
|
|
296
|
-
function setBody(
|
|
296
|
+
function setBody(
|
|
297
|
+
clonedPostman: sdk.Request,
|
|
298
|
+
body: Body,
|
|
299
|
+
encoding?: Record<string, { contentType?: string }>
|
|
300
|
+
) {
|
|
297
301
|
if (clonedPostman.body === undefined) {
|
|
298
302
|
return;
|
|
299
303
|
}
|
|
300
304
|
|
|
301
305
|
if (body.type === "empty") {
|
|
306
|
+
// When the original request has formdata and encoding is declared, keep the
|
|
307
|
+
// placeholder params so the code snippet reflects the selected encoding even
|
|
308
|
+
// before the user has uploaded a file.
|
|
309
|
+
if (
|
|
310
|
+
clonedPostman.body?.mode === "formdata" &&
|
|
311
|
+
encoding &&
|
|
312
|
+
Object.keys(encoding).length > 0
|
|
313
|
+
) {
|
|
314
|
+
const members: any[] =
|
|
315
|
+
(clonedPostman.body.formdata as any)?.members ?? [];
|
|
316
|
+
members.forEach((param: any) => {
|
|
317
|
+
const partContentType = encoding[param.key]?.contentType
|
|
318
|
+
?.split(",")[0]
|
|
319
|
+
.trim();
|
|
320
|
+
if (partContentType) {
|
|
321
|
+
param.contentType = partContentType;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
302
326
|
clonedPostman.body = undefined;
|
|
303
327
|
return;
|
|
304
328
|
}
|
|
@@ -336,14 +360,35 @@ function setBody(clonedPostman: sdk.Request, body: Body) {
|
|
|
336
360
|
Object.entries(body.content)
|
|
337
361
|
.filter((entry): entry is [string, NonNullable<Content>] => !!entry[1])
|
|
338
362
|
.forEach(([key, content]) => {
|
|
363
|
+
const partContentType = encoding?.[key]?.contentType
|
|
364
|
+
?.split(",")[0]
|
|
365
|
+
.trim();
|
|
339
366
|
if (content.type === "file") {
|
|
340
|
-
params.push(
|
|
367
|
+
params.push(
|
|
368
|
+
new sdk.FormParam({
|
|
369
|
+
key: key,
|
|
370
|
+
...content,
|
|
371
|
+
...(partContentType && { contentType: partContentType }),
|
|
372
|
+
})
|
|
373
|
+
);
|
|
341
374
|
} else if (content.type === "file[]") {
|
|
342
375
|
content.value.forEach((file) =>
|
|
343
|
-
params.push(
|
|
376
|
+
params.push(
|
|
377
|
+
new sdk.FormParam({
|
|
378
|
+
key,
|
|
379
|
+
value: file,
|
|
380
|
+
...(partContentType && { contentType: partContentType }),
|
|
381
|
+
})
|
|
382
|
+
)
|
|
344
383
|
);
|
|
345
384
|
} else {
|
|
346
|
-
params.push(
|
|
385
|
+
params.push(
|
|
386
|
+
new sdk.FormParam({
|
|
387
|
+
key: key,
|
|
388
|
+
value: content.value,
|
|
389
|
+
...(partContentType && { contentType: partContentType }),
|
|
390
|
+
})
|
|
391
|
+
);
|
|
347
392
|
}
|
|
348
393
|
});
|
|
349
394
|
params.forEach((param) => {
|
|
@@ -391,6 +436,7 @@ interface Options {
|
|
|
391
436
|
accept: string;
|
|
392
437
|
body: Body;
|
|
393
438
|
auth: AuthState;
|
|
439
|
+
encoding?: Record<string, { contentType?: string }>;
|
|
394
440
|
}
|
|
395
441
|
|
|
396
442
|
function buildPostmanRequest(
|
|
@@ -405,6 +451,7 @@ function buildPostmanRequest(
|
|
|
405
451
|
body,
|
|
406
452
|
server,
|
|
407
453
|
auth,
|
|
454
|
+
encoding,
|
|
408
455
|
}: Options
|
|
409
456
|
) {
|
|
410
457
|
const clonedPostman = cloneDeep(postman);
|
|
@@ -532,7 +579,7 @@ function buildPostmanRequest(
|
|
|
532
579
|
otherHeaders
|
|
533
580
|
);
|
|
534
581
|
|
|
535
|
-
setBody(clonedPostman, body);
|
|
582
|
+
setBody(clonedPostman, body, encoding);
|
|
536
583
|
|
|
537
584
|
return clonedPostman;
|
|
538
585
|
}
|
|
@@ -12,7 +12,7 @@ import CodeSnippets from "@theme/ApiExplorer/CodeSnippets";
|
|
|
12
12
|
import Request from "@theme/ApiExplorer/Request";
|
|
13
13
|
import Response from "@theme/ApiExplorer/Response";
|
|
14
14
|
import SecuritySchemes from "@theme/ApiExplorer/SecuritySchemes";
|
|
15
|
-
import { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
15
|
+
import type { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
|
|
16
16
|
import * as sdk from "postman-collection";
|
|
17
17
|
|
|
18
18
|
function ApiExplorer({
|
|
@@ -41,6 +41,7 @@ function ApiExplorer({
|
|
|
41
41
|
postman={postman}
|
|
42
42
|
codeSamples={(item as any)["x-codeSamples"] ?? []}
|
|
43
43
|
maskCredentials={mask_credentials}
|
|
44
|
+
requestBody={item.requestBody}
|
|
44
45
|
/>
|
|
45
46
|
)}
|
|
46
47
|
<Request item={item} />
|