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.
Files changed (29) hide show
  1. package/lib/theme/ApiExplorer/Authorization/slice.js +3 -1
  2. package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.d.ts +7 -0
  3. package/lib/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.js +126 -0
  4. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.d.ts +9 -0
  5. package/lib/theme/ApiExplorer/Body/FormBodyItem/index.js +110 -0
  6. package/lib/theme/ApiExplorer/Body/index.js +42 -97
  7. package/lib/theme/ApiExplorer/Body/slice.d.ts +27 -2
  8. package/lib/theme/ApiExplorer/Body/slice.js +22 -2
  9. package/lib/theme/ApiExplorer/LiveEditor/index.js +2 -3
  10. package/lib/theme/ApiExplorer/buildPostmanRequest.js +23 -7
  11. package/lib/theme/ApiExplorer/{persistanceMiddleware.d.ts → persistenceMiddleware.d.ts} +3 -3
  12. package/lib/theme/ApiExplorer/{persistanceMiddleware.js → persistenceMiddleware.js} +16 -9
  13. package/lib/theme/ApiExplorer/storage-utils.d.ts +2 -2
  14. package/lib/theme/ApiExplorer/storage-utils.js +3 -3
  15. package/lib/theme/ApiItem/index.js +12 -8
  16. package/lib/types.d.ts +7 -1
  17. package/package.json +3 -3
  18. package/src/theme/ApiExplorer/Authorization/slice.ts +1 -1
  19. package/src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx +77 -0
  20. package/src/theme/ApiExplorer/Body/FormBodyItem/index.tsx +120 -0
  21. package/src/theme/ApiExplorer/Body/index.tsx +39 -104
  22. package/src/theme/ApiExplorer/Body/slice.ts +40 -1
  23. package/src/theme/ApiExplorer/LiveEditor/index.tsx +2 -3
  24. package/src/theme/ApiExplorer/buildPostmanRequest.ts +23 -7
  25. package/src/theme/ApiExplorer/{persistanceMiddleware.ts → persistenceMiddleware.ts} +20 -12
  26. package/src/theme/ApiExplorer/storage-utils.ts +4 -4
  27. package/src/theme/ApiItem/index.tsx +12 -7
  28. package/src/types.ts +7 -1
  29. 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.createPersistanceMiddleware = createPersistanceMiddleware;
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 createPersistanceMiddleware(options) {
13
- const persistanceMiddleware = (storeAPI) => (next) => (action) => {
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)("sessionStorage");
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
- let serverObject = JSON.parse(server);
48
- serverObject.variables[variables.key].default = variables.value;
49
- storage.setItem("server", JSON.stringify(serverObject));
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 persistanceMiddleware;
60
+ return persistenceMiddleware;
54
61
  }
@@ -1,4 +1,4 @@
1
1
  export declare function hashArray(arr: string[]): string;
2
- type Persistance = false | "localStorage" | "sessionStorage" | undefined;
3
- export declare function createStorage(persistance: Persistance): Storage;
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(persistance) {
27
- if (persistance === false) {
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 (persistance === "sessionStorage") {
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 persistanceMiddleware_1 = require("@theme/ApiExplorer/persistanceMiddleware");
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 persistanceMiddleware = (0,
75
- persistanceMiddleware_1.createPersistanceMiddleware)(options);
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)({}, [persistanceMiddleware]);
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 = window?.sessionStorage.getItem("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.url ? serverObject : undefined,
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
- [persistanceMiddleware]
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
- authPersistance?: false | "localStorage" | "sessionStorage";
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-1083",
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-1083",
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": "cf5831415603ce841036073da0ff9e50db9ed9d8"
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
- clearFormBodyKey,
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
- <div>
134
- {Object.entries(schema.properties ?? {}).map(([key, val]: any) => {
135
- if (val.format === "binary") {
136
- return (
137
- <FormItem
138
- key={key}
139
- label={key}
140
- required={
141
- Array.isArray(schema.required) &&
142
- schema.required.includes(key)
143
- }
144
- >
145
- <FormFileUpload
146
- placeholder={val.description || key}
147
- onChange={(file: any) => {
148
- if (file === undefined) {
149
- dispatch(clearFormBodyKey(key));
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 action={dispatch} language={language} required={required}>
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 action={dispatch} language={language} required={required}>
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 action={dispatch} language={language}>
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 action={dispatch} language={language} required={required}>
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 = FileContent | StringContent | undefined;
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(setStringRawBody(code));
60
- }, [action, code]);
58
+ action(code);
59
+ }, [code]);
61
60
 
62
61
  const {
63
62
  control,