docusaurus-theme-openapi-docs 0.0.0-1083 → 0.0.0-1085
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/theme/ApiExplorer/Authorization/slice.js +3 -1
- package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.d.ts +7 -0
- package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +126 -0
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +9 -0
- package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +110 -0
- package/lib/theme/ApiExplorer/Body/index.js +42 -97
- package/lib/theme/ApiExplorer/Body/slice.d.ts +27 -2
- package/lib/theme/ApiExplorer/Body/slice.js +22 -2
- package/lib/theme/ApiExplorer/LiveEditor/index.js +2 -3
- package/lib/theme/ApiExplorer/buildPostmanRequest.js +23 -7
- package/lib/theme/ApiExplorer/{persistanceMiddleware.d.ts → persistenceMiddleware.d.ts} +3 -3
- package/lib/theme/ApiExplorer/{persistanceMiddleware.js → persistenceMiddleware.js} +16 -9
- package/lib/theme/ApiExplorer/storage-utils.d.ts +2 -2
- package/lib/theme/ApiExplorer/storage-utils.js +3 -3
- package/lib/theme/ApiItem/index.js +12 -8
- package/lib/types.d.ts +7 -1
- package/package.json +3 -3
- package/src/theme/ApiExplorer/Authorization/slice.ts +1 -1
- package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +77 -0
- package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +120 -0
- package/src/theme/ApiExplorer/Body/index.tsx +39 -104
- package/src/theme/ApiExplorer/Body/slice.ts +40 -1
- package/src/theme/ApiExplorer/LiveEditor/index.tsx +2 -3
- package/src/theme/ApiExplorer/buildPostmanRequest.ts +23 -7
- package/src/theme/ApiExplorer/{persistanceMiddleware.ts → persistenceMiddleware.ts} +20 -12
- package/src/theme/ApiExplorer/storage-utils.ts +4 -4
- package/src/theme/ApiItem/index.tsx +12 -7
- package/src/types.ts +7 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,14 +6,16 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
* ========================================================================== */
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.createPersistenceMiddleware = createPersistenceMiddleware;
|
|
10
10
|
const slice_1 = require("@theme/ApiExplorer/Authorization/slice");
|
|
11
11
|
const storage_utils_1 = require("./storage-utils");
|
|
12
|
-
function
|
|
13
|
-
const
|
|
12
|
+
function createPersistenceMiddleware(options) {
|
|
13
|
+
const persistenceMiddleware = (storeAPI) => (next) => (action) => {
|
|
14
14
|
const result = next(action);
|
|
15
15
|
const state = storeAPI.getState();
|
|
16
|
-
const storage = (0, storage_utils_1.createStorage)(
|
|
16
|
+
const storage = (0, storage_utils_1.createStorage)(
|
|
17
|
+
options?.authPersistence ?? "sessionStorage"
|
|
18
|
+
);
|
|
17
19
|
if (action.type === slice_1.setAuthData.type) {
|
|
18
20
|
for (const [key, value] of Object.entries(state.auth.data)) {
|
|
19
21
|
if (Object.values(value).filter(Boolean).length > 0) {
|
|
@@ -42,13 +44,18 @@ function createPersistanceMiddleware(options) {
|
|
|
42
44
|
storage.setItem("server", action.payload);
|
|
43
45
|
}
|
|
44
46
|
if (action.type === "server/setServerVariable") {
|
|
45
|
-
const server = storage.getItem("server")
|
|
47
|
+
const server = storage.getItem("server");
|
|
48
|
+
if (!server) {
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
46
51
|
const variables = JSON.parse(action.payload);
|
|
47
|
-
|
|
48
|
-
serverObject.variables[variables.key]
|
|
49
|
-
|
|
52
|
+
const serverObject = JSON.parse(server) ?? {};
|
|
53
|
+
if (serverObject.variables?.[variables.key]) {
|
|
54
|
+
serverObject.variables[variables.key].default = variables.value;
|
|
55
|
+
storage.setItem("server", JSON.stringify(serverObject));
|
|
56
|
+
}
|
|
50
57
|
}
|
|
51
58
|
return result;
|
|
52
59
|
};
|
|
53
|
-
return
|
|
60
|
+
return persistenceMiddleware;
|
|
54
61
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare function hashArray(arr: string[]): string;
|
|
2
|
-
type
|
|
3
|
-
export declare function createStorage(
|
|
2
|
+
type Persistence = false | "localStorage" | "sessionStorage" | undefined;
|
|
3
|
+
export declare function createStorage(persistence: Persistence): Storage;
|
|
4
4
|
export {};
|
|
@@ -23,8 +23,8 @@ function hashArray(arr) {
|
|
|
23
23
|
const res = hashed.join();
|
|
24
24
|
return hash(res);
|
|
25
25
|
}
|
|
26
|
-
function createStorage(
|
|
27
|
-
if (
|
|
26
|
+
function createStorage(persistence) {
|
|
27
|
+
if (persistence === false) {
|
|
28
28
|
return {
|
|
29
29
|
getItem: () => null,
|
|
30
30
|
setItem: () => {},
|
|
@@ -34,7 +34,7 @@ function createStorage(persistance) {
|
|
|
34
34
|
length: 0,
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
-
if (
|
|
37
|
+
if (persistence === "sessionStorage") {
|
|
38
38
|
return sessionStorage;
|
|
39
39
|
}
|
|
40
40
|
return localStorage;
|
|
@@ -24,7 +24,8 @@ const useDocusaurusContext_1 = __importDefault(
|
|
|
24
24
|
);
|
|
25
25
|
const useIsBrowser_1 = __importDefault(require("@docusaurus/useIsBrowser"));
|
|
26
26
|
const slice_1 = require("@theme/ApiExplorer/Authorization/slice");
|
|
27
|
-
const
|
|
27
|
+
const persistenceMiddleware_1 = require("@theme/ApiExplorer/persistenceMiddleware");
|
|
28
|
+
const storage_utils_1 = require("@theme/ApiExplorer/storage-utils");
|
|
28
29
|
const Layout_1 = __importDefault(require("@theme/ApiItem/Layout"));
|
|
29
30
|
const CodeBlock_1 = __importDefault(require("@theme/CodeBlock"));
|
|
30
31
|
const Metadata_1 = __importDefault(require("@theme/DocItem/Metadata"));
|
|
@@ -71,11 +72,11 @@ function ApiItem(props) {
|
|
|
71
72
|
const statusRegex = new RegExp("(20[0-9]|2[1-9][0-9])");
|
|
72
73
|
// Define store2
|
|
73
74
|
let store2 = {};
|
|
74
|
-
const
|
|
75
|
-
|
|
75
|
+
const persistenceMiddleware = (0,
|
|
76
|
+
persistenceMiddleware_1.createPersistenceMiddleware)(options);
|
|
76
77
|
// Init store for SSR
|
|
77
78
|
if (!isBrowser) {
|
|
78
|
-
store2 = (0, store_1.createStoreWithoutState)({}, [
|
|
79
|
+
store2 = (0, store_1.createStoreWithoutState)({}, [persistenceMiddleware]);
|
|
79
80
|
}
|
|
80
81
|
// Init store for CSR to hydrate components
|
|
81
82
|
if (isBrowser) {
|
|
@@ -106,11 +107,14 @@ function ApiItem(props) {
|
|
|
106
107
|
securitySchemes: api?.securitySchemes,
|
|
107
108
|
options,
|
|
108
109
|
});
|
|
110
|
+
const storage = (0, storage_utils_1.createStorage)(
|
|
111
|
+
options?.authPersistence ?? "sessionStorage"
|
|
112
|
+
);
|
|
109
113
|
// TODO: determine way to rehydrate without flashing
|
|
110
114
|
// const acceptValue = window?.sessionStorage.getItem("accept");
|
|
111
115
|
// const contentTypeValue = window?.sessionStorage.getItem("contentType");
|
|
112
|
-
const server =
|
|
113
|
-
const serverObject = JSON.parse(server)
|
|
116
|
+
const server = storage.getItem("server");
|
|
117
|
+
const serverObject = server ? JSON.parse(server) : undefined;
|
|
114
118
|
store2 = (0, store_1.createStoreWithState)(
|
|
115
119
|
{
|
|
116
120
|
accept: {
|
|
@@ -122,7 +126,7 @@ function ApiItem(props) {
|
|
|
122
126
|
options: contentTypeArray,
|
|
123
127
|
},
|
|
124
128
|
server: {
|
|
125
|
-
value: serverObject
|
|
129
|
+
value: serverObject?.url ? serverObject : undefined,
|
|
126
130
|
options: servers,
|
|
127
131
|
},
|
|
128
132
|
response: { value: undefined },
|
|
@@ -130,7 +134,7 @@ function ApiItem(props) {
|
|
|
130
134
|
params,
|
|
131
135
|
auth,
|
|
132
136
|
},
|
|
133
|
-
[
|
|
137
|
+
[persistenceMiddleware]
|
|
134
138
|
);
|
|
135
139
|
}
|
|
136
140
|
if (api) {
|
package/lib/types.d.ts
CHANGED
|
@@ -3,7 +3,13 @@ import type { JSONSchema4, JSONSchema6, JSONSchema7 } from "json-schema";
|
|
|
3
3
|
export interface ThemeConfig {
|
|
4
4
|
api?: {
|
|
5
5
|
proxy?: string;
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Controls how authentication credentials are persisted in the API explorer.
|
|
8
|
+
* - `false`: No persistence (in-memory only)
|
|
9
|
+
* - `"sessionStorage"`: Persist for the browser session (default)
|
|
10
|
+
* - `"localStorage"`: Persist across browser sessions
|
|
11
|
+
*/
|
|
12
|
+
authPersistence?: false | "sessionStorage" | "localStorage";
|
|
7
13
|
/** Request timeout in milliseconds. Defaults to 30000 (30 seconds). */
|
|
8
14
|
requestTimeout?: number;
|
|
9
15
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-theme-openapi-docs",
|
|
3
3
|
"description": "OpenAPI theme for Docusaurus.",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-1085",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@types/postman-collection": "^3.5.11",
|
|
39
39
|
"@types/react-modal": "^3.16.3",
|
|
40
40
|
"concurrently": "^9.2.0",
|
|
41
|
-
"docusaurus-plugin-openapi-docs": "0.0.0-
|
|
41
|
+
"docusaurus-plugin-openapi-docs": "0.0.0-1085",
|
|
42
42
|
"docusaurus-plugin-sass": "^0.2.6",
|
|
43
43
|
"eslint-plugin-prettier": "^5.5.1"
|
|
44
44
|
},
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=14"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "26311f52652bf29d0ca59389d5f39707320f1baf"
|
|
85
85
|
}
|
|
@@ -58,7 +58,7 @@ export function createAuth({
|
|
|
58
58
|
};
|
|
59
59
|
options?: ThemeConfig["api"];
|
|
60
60
|
}): AuthState {
|
|
61
|
-
const storage = createStorage("sessionStorage");
|
|
61
|
+
const storage = createStorage(opts?.authPersistence ?? "sessionStorage");
|
|
62
62
|
|
|
63
63
|
let data: AuthState["data"] = {};
|
|
64
64
|
let options: AuthState["options"] = {};
|
|
@@ -0,0 +1,77 @@
|
|
|
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, { useState } from "react";
|
|
9
|
+
import FormFileUpload from "@theme/ApiExplorer/FormFileUpload";
|
|
10
|
+
import { useTypedDispatch } from "@theme/ApiItem/hooks";
|
|
11
|
+
import { FileContent, setFileArrayFormBody } from "../slice";
|
|
12
|
+
|
|
13
|
+
interface FileArrayFormItemProps {
|
|
14
|
+
id: string;
|
|
15
|
+
description: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default function FileArrayFormBodyItem({
|
|
19
|
+
id,
|
|
20
|
+
description,
|
|
21
|
+
}: FileArrayFormItemProps): React.JSX.Element {
|
|
22
|
+
const dispatch = useTypedDispatch();
|
|
23
|
+
const [fileItems, setFileItems] = useState<
|
|
24
|
+
Map<number, FileContent["value"] | undefined>
|
|
25
|
+
>(new Map([[0, undefined]]));
|
|
26
|
+
|
|
27
|
+
const handleFileChange = (index: number, file: any) => {
|
|
28
|
+
const newItems = new Map(fileItems);
|
|
29
|
+
|
|
30
|
+
if (file === undefined) {
|
|
31
|
+
newItems.delete(index);
|
|
32
|
+
|
|
33
|
+
setFileItems(newItems);
|
|
34
|
+
|
|
35
|
+
dispatch(
|
|
36
|
+
setFileArrayFormBody({
|
|
37
|
+
key: id,
|
|
38
|
+
value: [...newItems.values()].filter((item) => item !== undefined),
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let maxIndex = 0;
|
|
45
|
+
|
|
46
|
+
newItems.keys().forEach((item) => {
|
|
47
|
+
maxIndex = item > maxIndex ? item : maxIndex;
|
|
48
|
+
});
|
|
49
|
+
newItems.set(index, {
|
|
50
|
+
src: `/path/to/${file.name}`,
|
|
51
|
+
content: file,
|
|
52
|
+
});
|
|
53
|
+
newItems.set(index + 1, undefined);
|
|
54
|
+
|
|
55
|
+
setFileItems(newItems);
|
|
56
|
+
|
|
57
|
+
dispatch(
|
|
58
|
+
setFileArrayFormBody({
|
|
59
|
+
key: id,
|
|
60
|
+
value: [...newItems.values()].filter((item) => item !== undefined),
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div>
|
|
67
|
+
{[...fileItems.keys()].map((index) => (
|
|
68
|
+
<div key={index}>
|
|
69
|
+
<FormFileUpload
|
|
70
|
+
placeholder={description || id}
|
|
71
|
+
onChange={(file: any) => handleFileChange(index, file)}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
))}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
import FormFileUpload from "@theme/ApiExplorer/FormFileUpload";
|
|
10
|
+
import FormSelect from "@theme/ApiExplorer/FormSelect";
|
|
11
|
+
import FormTextInput from "@theme/ApiExplorer/FormTextInput";
|
|
12
|
+
import LiveApp from "@theme/ApiExplorer/LiveEditor";
|
|
13
|
+
import { useTypedDispatch } from "@theme/ApiItem/hooks";
|
|
14
|
+
import { SchemaObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
15
|
+
import { clearFormBodyKey, setFileFormBody, setStringFormBody } from "../slice";
|
|
16
|
+
import FileArrayFormBodyItem from "../FileArrayFormBodyItem";
|
|
17
|
+
|
|
18
|
+
interface FormBodyItemProps {
|
|
19
|
+
schemaObject: SchemaObject;
|
|
20
|
+
id: string;
|
|
21
|
+
schema: SchemaObject;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default function FormBodyItem({
|
|
25
|
+
schemaObject,
|
|
26
|
+
id,
|
|
27
|
+
schema,
|
|
28
|
+
}: FormBodyItemProps): React.JSX.Element {
|
|
29
|
+
const dispatch = useTypedDispatch();
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
schemaObject.type === "array" &&
|
|
33
|
+
schemaObject.items?.format === "binary"
|
|
34
|
+
) {
|
|
35
|
+
return (
|
|
36
|
+
<FileArrayFormBodyItem id={id} description={schemaObject.description} />
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (schemaObject.format === "binary") {
|
|
41
|
+
return (
|
|
42
|
+
<FormFileUpload
|
|
43
|
+
placeholder={schemaObject.description || id}
|
|
44
|
+
onChange={(file: any) => {
|
|
45
|
+
if (file === undefined) {
|
|
46
|
+
dispatch(clearFormBodyKey(id));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
dispatch(
|
|
50
|
+
setFileFormBody({
|
|
51
|
+
key: id,
|
|
52
|
+
value: {
|
|
53
|
+
src: `/path/to/${file.name}`,
|
|
54
|
+
content: file,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
schemaObject.type === "object" &&
|
|
65
|
+
(schemaObject.example || schemaObject.examples)
|
|
66
|
+
) {
|
|
67
|
+
const objectExample = JSON.stringify(
|
|
68
|
+
schemaObject.example ?? schemaObject.examples[0],
|
|
69
|
+
null,
|
|
70
|
+
2
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<LiveApp
|
|
75
|
+
action={(code: string) =>
|
|
76
|
+
dispatch(setStringFormBody({ key: id, value: code }))
|
|
77
|
+
}
|
|
78
|
+
>
|
|
79
|
+
{objectExample}
|
|
80
|
+
</LiveApp>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
schemaObject.enum &&
|
|
86
|
+
schemaObject.enum.every((value) => typeof value === "string")
|
|
87
|
+
) {
|
|
88
|
+
return (
|
|
89
|
+
<FormSelect
|
|
90
|
+
options={["---", ...schemaObject.enum]}
|
|
91
|
+
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
92
|
+
const val = e.target.value;
|
|
93
|
+
if (val === "---") {
|
|
94
|
+
dispatch(clearFormBodyKey(id));
|
|
95
|
+
} else {
|
|
96
|
+
dispatch(
|
|
97
|
+
setStringFormBody({
|
|
98
|
+
key: id,
|
|
99
|
+
value: val,
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
// TODO: support all the other types.
|
|
108
|
+
return (
|
|
109
|
+
<FormTextInput
|
|
110
|
+
paramName={id}
|
|
111
|
+
isRequired={
|
|
112
|
+
Array.isArray(schema.required) && schema.required.includes(id)
|
|
113
|
+
}
|
|
114
|
+
placeholder={schemaObject.description || id}
|
|
115
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
116
|
+
dispatch(setStringFormBody({ key: id, value: e.target.value }));
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -12,8 +12,6 @@ import { translate } from "@docusaurus/Translate";
|
|
|
12
12
|
import json2xml from "@theme/ApiExplorer/Body/json2xml";
|
|
13
13
|
import FormFileUpload from "@theme/ApiExplorer/FormFileUpload";
|
|
14
14
|
import FormItem from "@theme/ApiExplorer/FormItem";
|
|
15
|
-
import FormSelect from "@theme/ApiExplorer/FormSelect";
|
|
16
|
-
import FormTextInput from "@theme/ApiExplorer/FormTextInput";
|
|
17
15
|
import LiveApp from "@theme/ApiExplorer/LiveEditor";
|
|
18
16
|
import { useTypedDispatch, useTypedSelector } from "@theme/ApiItem/hooks";
|
|
19
17
|
import Markdown from "@theme/Markdown";
|
|
@@ -23,13 +21,8 @@ import { OPENAPI_BODY, OPENAPI_REQUEST } from "@theme/translationIds";
|
|
|
23
21
|
import { RequestBodyObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
|
24
22
|
import format from "xml-formatter";
|
|
25
23
|
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
clearRawBody,
|
|
29
|
-
setFileFormBody,
|
|
30
|
-
setFileRawBody,
|
|
31
|
-
setStringFormBody,
|
|
32
|
-
} from "./slice";
|
|
24
|
+
import { clearRawBody, setFileRawBody, setStringRawBody } from "./slice";
|
|
25
|
+
import FormBodyItem from "./FormBodyItem";
|
|
33
26
|
|
|
34
27
|
export interface Props {
|
|
35
28
|
jsonRequestBodyExample: string;
|
|
@@ -130,96 +123,23 @@ function Body({
|
|
|
130
123
|
) {
|
|
131
124
|
return (
|
|
132
125
|
<FormItem className="openapi-explorer__form-item-body-container">
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
dispatch(
|
|
153
|
-
setFileFormBody({
|
|
154
|
-
key: key,
|
|
155
|
-
value: {
|
|
156
|
-
src: `/path/to/${file.name}`,
|
|
157
|
-
content: file,
|
|
158
|
-
},
|
|
159
|
-
})
|
|
160
|
-
);
|
|
161
|
-
}}
|
|
162
|
-
/>
|
|
163
|
-
</FormItem>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (val.enum) {
|
|
168
|
-
return (
|
|
169
|
-
<FormItem
|
|
170
|
-
key={key}
|
|
171
|
-
label={key}
|
|
172
|
-
required={
|
|
173
|
-
Array.isArray(schema.required) &&
|
|
174
|
-
schema.required.includes(key)
|
|
175
|
-
}
|
|
176
|
-
>
|
|
177
|
-
<FormSelect
|
|
178
|
-
options={["---", ...val.enum]}
|
|
179
|
-
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
180
|
-
const val = e.target.value;
|
|
181
|
-
if (val === "---") {
|
|
182
|
-
dispatch(clearFormBodyKey(key));
|
|
183
|
-
} else {
|
|
184
|
-
dispatch(
|
|
185
|
-
setStringFormBody({
|
|
186
|
-
key: key,
|
|
187
|
-
value: val,
|
|
188
|
-
})
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
}}
|
|
192
|
-
/>
|
|
193
|
-
</FormItem>
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
// TODO: support all the other types.
|
|
197
|
-
return (
|
|
198
|
-
<FormItem
|
|
199
|
-
key={key}
|
|
200
|
-
label={key}
|
|
201
|
-
required={
|
|
202
|
-
Array.isArray(schema.required) &&
|
|
203
|
-
schema.required.includes(key)
|
|
204
|
-
}
|
|
205
|
-
>
|
|
206
|
-
<FormTextInput
|
|
207
|
-
paramName={key}
|
|
208
|
-
isRequired={
|
|
209
|
-
Array.isArray(schema.required) &&
|
|
210
|
-
schema.required.includes(key)
|
|
211
|
-
}
|
|
212
|
-
placeholder={val.description || key}
|
|
213
|
-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
214
|
-
dispatch(
|
|
215
|
-
setStringFormBody({ key: key, value: e.target.value })
|
|
216
|
-
);
|
|
217
|
-
}}
|
|
218
|
-
/>
|
|
219
|
-
</FormItem>
|
|
220
|
-
);
|
|
221
|
-
})}
|
|
222
|
-
</div>
|
|
126
|
+
{Object.entries(schema.properties ?? {}).map(([key, val]: any) => {
|
|
127
|
+
return (
|
|
128
|
+
<FormItem
|
|
129
|
+
key={key}
|
|
130
|
+
label={key}
|
|
131
|
+
required={
|
|
132
|
+
Array.isArray(schema.required) && schema.required.includes(key)
|
|
133
|
+
}
|
|
134
|
+
>
|
|
135
|
+
<FormBodyItem
|
|
136
|
+
schemaObject={val}
|
|
137
|
+
id={key}
|
|
138
|
+
schema={schema}
|
|
139
|
+
></FormBodyItem>
|
|
140
|
+
</FormItem>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
223
143
|
</FormItem>
|
|
224
144
|
);
|
|
225
145
|
}
|
|
@@ -348,7 +268,11 @@ function Body({
|
|
|
348
268
|
value="Example (from schema)"
|
|
349
269
|
default
|
|
350
270
|
>
|
|
351
|
-
<LiveApp
|
|
271
|
+
<LiveApp
|
|
272
|
+
action={(code: string) => dispatch(setStringRawBody(code))}
|
|
273
|
+
language={language}
|
|
274
|
+
required={required}
|
|
275
|
+
>
|
|
352
276
|
{defaultBody}
|
|
353
277
|
</LiveApp>
|
|
354
278
|
</TabItem>
|
|
@@ -357,7 +281,7 @@ function Body({
|
|
|
357
281
|
{example.summary && <Markdown>{example.summary}</Markdown>}
|
|
358
282
|
{exampleBody && (
|
|
359
283
|
<LiveApp
|
|
360
|
-
action={dispatch}
|
|
284
|
+
action={(code: string) => dispatch(setStringRawBody(code))}
|
|
361
285
|
language={language}
|
|
362
286
|
required={required}
|
|
363
287
|
>
|
|
@@ -383,7 +307,11 @@ function Body({
|
|
|
383
307
|
value="Example (from schema)"
|
|
384
308
|
default
|
|
385
309
|
>
|
|
386
|
-
<LiveApp
|
|
310
|
+
<LiveApp
|
|
311
|
+
action={(code: string) => dispatch(setStringRawBody(code))}
|
|
312
|
+
language={language}
|
|
313
|
+
required={required}
|
|
314
|
+
>
|
|
387
315
|
{defaultBody}
|
|
388
316
|
</LiveApp>
|
|
389
317
|
</TabItem>
|
|
@@ -397,7 +325,10 @@ function Body({
|
|
|
397
325
|
>
|
|
398
326
|
{example.summary && <Markdown>{example.summary}</Markdown>}
|
|
399
327
|
{example.body && (
|
|
400
|
-
<LiveApp
|
|
328
|
+
<LiveApp
|
|
329
|
+
action={(code: string) => dispatch(setStringRawBody(code))}
|
|
330
|
+
language={language}
|
|
331
|
+
>
|
|
401
332
|
{example.body}
|
|
402
333
|
</LiveApp>
|
|
403
334
|
)}
|
|
@@ -411,7 +342,11 @@ function Body({
|
|
|
411
342
|
|
|
412
343
|
return (
|
|
413
344
|
<FormItem>
|
|
414
|
-
<LiveApp
|
|
345
|
+
<LiveApp
|
|
346
|
+
action={(code: string) => dispatch(setStringRawBody(code))}
|
|
347
|
+
language={language}
|
|
348
|
+
required={required}
|
|
349
|
+
>
|
|
415
350
|
{defaultBody}
|
|
416
351
|
</LiveApp>
|
|
417
352
|
</FormItem>
|
|
@@ -15,12 +15,24 @@ export interface FileContent {
|
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export interface FileArrayContent {
|
|
19
|
+
type: "file[]";
|
|
20
|
+
value: {
|
|
21
|
+
src: string;
|
|
22
|
+
content: Blob;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
export interface StringContent {
|
|
19
27
|
type: "string";
|
|
20
28
|
value?: string;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
|
-
export type Content =
|
|
31
|
+
export type Content =
|
|
32
|
+
| FileContent
|
|
33
|
+
| FileArrayContent
|
|
34
|
+
| StringContent
|
|
35
|
+
| undefined;
|
|
24
36
|
|
|
25
37
|
export interface FormBody {
|
|
26
38
|
type: "form";
|
|
@@ -118,6 +130,32 @@ export const slice = createSlice({
|
|
|
118
130
|
};
|
|
119
131
|
return state;
|
|
120
132
|
},
|
|
133
|
+
setFileArrayFormBody: (
|
|
134
|
+
state,
|
|
135
|
+
action: PayloadAction<{
|
|
136
|
+
key: string;
|
|
137
|
+
value: FileArrayContent["value"];
|
|
138
|
+
}>
|
|
139
|
+
) => {
|
|
140
|
+
if (state?.type !== "form") {
|
|
141
|
+
return {
|
|
142
|
+
type: "form",
|
|
143
|
+
content: {
|
|
144
|
+
[action.payload.key]: {
|
|
145
|
+
type: "file[]",
|
|
146
|
+
value: action.payload.value,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
state.content[action.payload.key] = {
|
|
153
|
+
type: "file[]",
|
|
154
|
+
value: action.payload.value,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return state;
|
|
158
|
+
},
|
|
121
159
|
},
|
|
122
160
|
});
|
|
123
161
|
|
|
@@ -128,6 +166,7 @@ export const {
|
|
|
128
166
|
clearFormBodyKey,
|
|
129
167
|
setStringFormBody,
|
|
130
168
|
setFileFormBody,
|
|
169
|
+
setFileArrayFormBody,
|
|
131
170
|
} = slice.actions;
|
|
132
171
|
|
|
133
172
|
export default slice.reducer;
|
|
@@ -11,7 +11,6 @@ import { usePrismTheme } from "@docusaurus/theme-common";
|
|
|
11
11
|
import { translate } from "@docusaurus/Translate";
|
|
12
12
|
import useIsBrowser from "@docusaurus/useIsBrowser";
|
|
13
13
|
import { ErrorMessage } from "@hookform/error-message";
|
|
14
|
-
import { setStringRawBody } from "@theme/ApiExplorer/Body/slice";
|
|
15
14
|
import { OPENAPI_FORM } from "@theme/translationIds";
|
|
16
15
|
import clsx from "clsx";
|
|
17
16
|
import { Controller, useFormContext } from "react-hook-form";
|
|
@@ -56,8 +55,8 @@ function App({
|
|
|
56
55
|
const [code, setCode] = React.useState(children.replace(/\n$/, ""));
|
|
57
56
|
|
|
58
57
|
useEffect(() => {
|
|
59
|
-
action(
|
|
60
|
-
}, [
|
|
58
|
+
action(code);
|
|
59
|
+
}, [code]);
|
|
61
60
|
|
|
62
61
|
const {
|
|
63
62
|
control,
|