Skip to content

Commit bb3c4fb

Browse files
authored
Enable multiselect in form-urlencoded body (#220)
1 parent 11a5067 commit bb3c4fb

File tree

4 files changed

+152
-3
lines changed

4 files changed

+152
-3
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
openapi: 3.0.3
2+
info:
3+
version: 1.0.0
4+
title: ""
5+
servers:
6+
- url: https://example.com
7+
security:
8+
- basic_auth: []
9+
paths:
10+
/Calls:
11+
post:
12+
tags:
13+
- Calls
14+
operationId: create_a_call
15+
summary: Create a Call
16+
requestBody:
17+
required: true
18+
content:
19+
application/x-www-form-urlencoded:
20+
schema:
21+
type: object
22+
properties:
23+
StatusCallback:
24+
type: string
25+
example: https://your-api-endpoint.com/path
26+
StatusCallbackEvent:
27+
type: array
28+
items:
29+
type: string
30+
enum:
31+
- initiated
32+
- ringing
33+
- answered
34+
- completed
35+
example:
36+
- completed
37+
encoding:
38+
StatusCallbackEvent:
39+
style: form
40+
explode: true
41+
responses:
42+
"200":
43+
description: OK

packages/docusaurus-theme-openapi/src/theme/ApiDemoPanel/Body/index.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import React from "react";
1010
import { RequestBodyObject } from "docusaurus-plugin-openapi/src/openapi/types";
1111

1212
import ContentType from "../ContentType";
13+
import FormMultiSelect from "../FormMultiSelect";
1314
import FormSelect from "../FormSelect";
1415
import { useTypedDispatch, useTypedSelector } from "../hooks";
1516
import FormFileUpload from "./../FormFileUpload";
@@ -22,6 +23,7 @@ import {
2223
setFileFormBody,
2324
setFileRawBody,
2425
setStringFormBody,
26+
setArrayFormBody,
2527
setStringRawBody,
2628
} from "./slice";
2729

@@ -165,6 +167,37 @@ function Body({ requestBodyMetadata, jsonRequestBodyExample }: Props) {
165167
</FormItem>
166168
);
167169
}
170+
171+
if (
172+
val.type === "array" &&
173+
val.items.enum &&
174+
val.items.type === "string"
175+
) {
176+
return (
177+
<FormItem key={key} label={key}>
178+
<FormMultiSelect
179+
options={val.items.enum}
180+
onChange={(e) => {
181+
const values = Array.prototype.filter
182+
.call(e.target.options, (o) => o.selected)
183+
.map((o) => o.value);
184+
185+
if (values.length === 0) {
186+
dispatch(clearFormBodyKey(key));
187+
} else {
188+
dispatch(
189+
setArrayFormBody({
190+
key: key,
191+
value: values,
192+
})
193+
);
194+
}
195+
}}
196+
/>
197+
</FormItem>
198+
);
199+
}
200+
168201
// TODO: support all the other types.
169202
return (
170203
<FormItem key={key} label={key}>

packages/docusaurus-theme-openapi/src/theme/ApiDemoPanel/Body/slice.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@ export interface StringContent {
2020
value?: string;
2121
}
2222

23-
export type Content = FileContent | StringContent | undefined;
23+
export type ArrayContent = {
24+
type: "array";
25+
value?: {
26+
type: "string";
27+
value?: string[];
28+
};
29+
};
30+
31+
export type Content = FileContent | StringContent | ArrayContent | undefined;
2432

2533
export interface FormBody {
2634
type: "form";
@@ -31,7 +39,7 @@ export interface FormBody {
3139

3240
export interface RawBody {
3341
type: "raw";
34-
content: Content;
42+
content: Exclude<Content, ArrayContent>;
3543
}
3644

3745
export interface EmptyBody {
@@ -97,6 +105,33 @@ export const slice = createSlice({
97105
};
98106
return state;
99107
},
108+
setArrayFormBody: (
109+
state,
110+
action: PayloadAction<{ key: string; value: string[] }>
111+
) => {
112+
if (state?.type !== "form") {
113+
return {
114+
type: "form",
115+
content: {
116+
[action.payload.key]: {
117+
type: "array",
118+
value: {
119+
type: "string",
120+
value: action.payload.value,
121+
},
122+
},
123+
},
124+
};
125+
}
126+
state.content[action.payload.key] = {
127+
type: "array",
128+
value: {
129+
type: "string",
130+
value: action.payload.value,
131+
},
132+
};
133+
return state;
134+
},
100135
setFileFormBody: (
101136
state,
102137
action: PayloadAction<{ key: string; value: FileContent["value"] }>
@@ -127,6 +162,7 @@ export const {
127162
setFileRawBody,
128163
clearFormBodyKey,
129164
setStringFormBody,
165+
setArrayFormBody,
130166
setFileFormBody,
131167
} = slice.actions;
132168

packages/docusaurus-theme-openapi/src/theme/ApiDemoPanel/buildPostmanRequest.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,51 @@ function setBody(clonedPostman: sdk.Request, body: Body) {
172172
}
173173
const params = Object.entries(body.content)
174174
.filter((entry): entry is [string, NonNullable<Content>] => !!entry[1])
175+
.filter(([_key, content]) => content.type !== "array")
175176
.map(([key, content]) => {
176-
if (content.type !== "file" && content.value) {
177+
if (
178+
content.type !== "file" &&
179+
content.type !== "array" &&
180+
content.value
181+
) {
177182
return new sdk.QueryParam({ key: key, value: content.value });
178183
}
179184
return undefined;
180185
})
181186
.filter((item): item is sdk.QueryParam => item !== undefined);
187+
188+
const arrayParams = Object.entries(body.content)
189+
.filter((entry): entry is [string, NonNullable<Content>] => !!entry[1])
190+
.filter(([_key, content]) => content.type === "array")
191+
.map(([key, content]) => {
192+
if (content.type === "array" && content.value) {
193+
return {
194+
key: key,
195+
values: content.value?.value?.map(
196+
(e) => new sdk.QueryParam({ key: key, value: e })
197+
),
198+
};
199+
}
200+
return undefined;
201+
})
202+
.filter((item) => item !== undefined && item?.values !== undefined);
203+
182204
clonedPostman.body.urlencoded?.assimilate(params, false);
205+
206+
// Now let's append the array keys
207+
for (const arrayParam of arrayParams) {
208+
clonedPostman.body.urlencoded?.remove(
209+
(e) => e.key === arrayParam?.key,
210+
undefined
211+
);
212+
213+
arrayParam?.values?.forEach((queryParam) =>
214+
clonedPostman.body?.urlencoded?.append(queryParam)
215+
);
216+
}
217+
218+
console.log(clonedPostman.body.urlencoded);
219+
183220
return;
184221
}
185222
default:

0 commit comments

Comments
 (0)