Skip to content

Commit b9b32c9

Browse files
authored
feat: Allow to skip submitting empty values in form data (#5830)
1 parent eaca2f6 commit b9b32c9

File tree

10 files changed

+75
-27
lines changed

10 files changed

+75
-27
lines changed

src/core/components/parameter-include-empty.jsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
11
import React from "react"
22
import cx from "classnames"
33
import PropTypes from "prop-types"
4-
import ImPropTypes from "react-immutable-proptypes"
54

6-
export const ParameterIncludeEmpty = ({ param, isIncluded, onChange, isDisabled }) => {
5+
export const ParameterIncludeEmpty = ({ isIncluded, onChange, isDisabled }) => {
76
const onCheckboxChange = e => {
87
onChange(e.target.checked)
98
}
10-
if(!param.get("allowEmptyValue")) {
11-
return null
12-
}
13-
return <div className={cx("parameter__empty_value_toggle", {
9+
return <label className={cx("parameter__empty_value_toggle", {
1410
"disabled": isDisabled
1511
})}>
1612
<input type="checkbox" disabled={isDisabled} checked={!isDisabled && isIncluded} onChange={onCheckboxChange} />
1713
Send empty value
18-
</div>
14+
</label>
1915
}
2016
ParameterIncludeEmpty.propTypes = {
21-
param: ImPropTypes.map.isRequired,
2217
isIncluded: PropTypes.bool.isRequired,
2318
isDisabled: PropTypes.bool.isRequired,
2419
onChange: PropTypes.func.isRequired,

src/core/components/parameter-row.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Map, List } from "immutable"
33
import PropTypes from "prop-types"
44
import ImPropTypes from "react-immutable-proptypes"
55
import win from "core/window"
6-
import { getSampleSchema, getExtensions, getCommonExtensions, numberToString, stringify } from "core/utils"
6+
import { getSampleSchema, getExtensions, getCommonExtensions, numberToString, stringify, isEmptyValue } from "core/utils"
77
import getParameterSchema from "../../helpers/get-parameter-schema.js"
88

99
export default class ParameterRow extends Component {
@@ -336,12 +336,11 @@ export default class ParameterRow extends Component {
336336
}
337337

338338
{
339-
!bodyParam && isExecute ?
339+
!bodyParam && isExecute && param.get("allowEmptyValue") ?
340340
<ParameterIncludeEmpty
341341
onChange={this.onChangeIncludeEmpty}
342342
isIncluded={specSelectors.parameterInclusionSettingFor(pathMethod, param.get("name"), param.get("in"))}
343-
isDisabled={value && value.size !== 0}
344-
param={param} />
343+
isDisabled={!isEmptyValue(value)} />
345344
: null
346345
}
347346

src/core/components/parameters/parameters.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export default class Parameters extends Component {
196196
specPath={specPath.slice(0, -1).push("requestBody")}
197197
requestBody={requestBody}
198198
requestBodyValue={oas3Selectors.requestBodyValue(...pathMethod)}
199+
requestBodyInclusionSetting={oas3Selectors.requestBodyInclusionSetting(...pathMethod)}
199200
isExecute={isExecute}
200201
activeExamplesKey={oas3Selectors.activeExamplesMember(
201202
...pathMethod,
@@ -222,6 +223,13 @@ export default class Parameters extends Component {
222223
}
223224
oas3Actions.setRequestBodyValue({ value, pathMethod })
224225
}}
226+
onChangeIncludeEmpty={(name, value) => {
227+
oas3Actions.setRequestBodyInclusion({
228+
pathMethod,
229+
value,
230+
name,
231+
})
232+
}}
225233
contentType={oas3Selectors.requestContentType(...pathMethod)}/>
226234
</div>
227235
</div>

src/core/plugins/oas3/actions.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
export const UPDATE_SELECTED_SERVER = "oas3_set_servers"
55
export const UPDATE_REQUEST_BODY_VALUE = "oas3_set_request_body_value"
6+
export const UPDATE_REQUEST_BODY_INCLUSION = "oas3_set_request_body_inclusion"
67
export const UPDATE_ACTIVE_EXAMPLES_MEMBER = "oas3_set_active_examples_member"
78
export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type"
89
export const UPDATE_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type"
@@ -22,6 +23,13 @@ export function setRequestBodyValue ({ value, pathMethod }) {
2223
}
2324
}
2425

26+
export function setRequestBodyInclusion ({ value, pathMethod, name }) {
27+
return {
28+
type: UPDATE_REQUEST_BODY_INCLUSION,
29+
payload: { value, pathMethod, name }
30+
}
31+
}
32+
2533
export function setActiveExamplesMember ({ name, pathMethod, contextType, contextName }) {
2634
return {
2735
type: UPDATE_ACTIVE_EXAMPLES_MEMBER,

src/core/plugins/oas3/components/request-body.jsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react"
22
import PropTypes from "prop-types"
33
import ImPropTypes from "react-immutable-proptypes"
44
import { Map, OrderedMap, List } from "immutable"
5-
import { getCommonExtensions, getSampleSchema, stringify } from "core/utils"
5+
import { getCommonExtensions, getSampleSchema, stringify, isEmptyValue } from "core/utils"
66

77
function getDefaultRequestBodyValue(requestBody, mediaType, activeExamplesKey) {
88
let mediaTypeValue = requestBody.getIn(["content", mediaType])
@@ -37,6 +37,7 @@ function getDefaultRequestBodyValue(requestBody, mediaType, activeExamplesKey) {
3737
const RequestBody = ({
3838
requestBody,
3939
requestBodyValue,
40+
requestBodyInclusionSetting,
4041
getComponent,
4142
getConfigs,
4243
specSelectors,
@@ -45,6 +46,7 @@ const RequestBody = ({
4546
isExecute,
4647
specPath,
4748
onChange,
49+
onChangeIncludeEmpty,
4850
activeExamplesKey,
4951
updateActiveExamplesKey,
5052
}) => {
@@ -58,6 +60,7 @@ const RequestBody = ({
5860
const HighlightCode = getComponent("highlightCode")
5961
const ExamplesSelectValueRetainer = getComponent("ExamplesSelectValueRetainer")
6062
const Example = getComponent("Example")
63+
const ParameterIncludeEmpty = getComponent("ParameterIncludeEmpty")
6164

6265
const { showCommonExtensions } = getConfigs()
6366

@@ -155,17 +158,26 @@ const RequestBody = ({
155158
</td>
156159
<td className="parameters-col_description">
157160
<Markdown source={ description }></Markdown>
158-
{isExecute ? <div><JsonSchemaForm
159-
fn={fn}
160-
dispatchInitialValue={!isFile}
161-
schema={prop}
162-
description={key}
163-
getComponent={getComponent}
164-
value={currentValue === undefined ? initialValue : currentValue}
165-
onChange={(value) => {
166-
onChange(value, [key])
167-
}}
168-
/></div> : null }
161+
{isExecute ? <div>
162+
<JsonSchemaForm
163+
fn={fn}
164+
dispatchInitialValue={!isFile}
165+
schema={prop}
166+
description={key}
167+
getComponent={getComponent}
168+
value={currentValue === undefined ? initialValue : currentValue}
169+
onChange={(value) => {
170+
onChange(value, [key])
171+
}}
172+
/>
173+
{required ? null : (
174+
<ParameterIncludeEmpty
175+
onChange={(value) => onChangeIncludeEmpty(key, value)}
176+
isIncluded={requestBodyInclusionSetting.get(key)}
177+
isDisabled={!isEmptyValue(currentValue)}
178+
/>
179+
)}
180+
</div> : null }
169181
</td>
170182
</tr>
171183
})
@@ -242,13 +254,15 @@ const RequestBody = ({
242254
RequestBody.propTypes = {
243255
requestBody: ImPropTypes.orderedMap.isRequired,
244256
requestBodyValue: ImPropTypes.orderedMap.isRequired,
257+
requestBodyInclusionSetting: ImPropTypes.Map.isRequired,
245258
getComponent: PropTypes.func.isRequired,
246259
getConfigs: PropTypes.func.isRequired,
247260
fn: PropTypes.object.isRequired,
248261
specSelectors: PropTypes.object.isRequired,
249262
contentType: PropTypes.string,
250263
isExecute: PropTypes.bool.isRequired,
251264
onChange: PropTypes.func.isRequired,
265+
onChangeIncludeEmpty: PropTypes.func.isRequired,
252266
specPath: PropTypes.array.isRequired,
253267
activeExamplesKey: PropTypes.string,
254268
updateActiveExamplesKey: PropTypes.func,

src/core/plugins/oas3/reducers.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
UPDATE_SELECTED_SERVER,
33
UPDATE_REQUEST_BODY_VALUE,
4+
UPDATE_REQUEST_BODY_INCLUSION,
45
UPDATE_ACTIVE_EXAMPLES_MEMBER,
56
UPDATE_REQUEST_CONTENT_TYPE,
67
UPDATE_SERVER_VARIABLE_VALUE,
@@ -16,6 +17,10 @@ export default {
1617
let [path, method] = pathMethod
1718
return state.setIn( [ "requestData", path, method, "bodyValue" ], value)
1819
},
20+
[UPDATE_REQUEST_BODY_INCLUSION]: (state, { payload: { value, pathMethod, name } } ) =>{
21+
let [path, method] = pathMethod
22+
return state.setIn( [ "requestData", path, method, "bodyInclusion", name ], value)
23+
},
1924
[UPDATE_ACTIVE_EXAMPLES_MEMBER]: (state, { payload: { name, pathMethod, contextType, contextName } } ) =>{
2025
let [path, method] = pathMethod
2126
return state.setIn( [ "examples", path, method, contextType, contextName, "activeExample" ], name)

src/core/plugins/oas3/selectors.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { OrderedMap } from "immutable"
1+
import { OrderedMap, Map } from "immutable"
22
import { isOAS3 as isOAS3Helper } from "./helpers"
33

44

@@ -26,6 +26,11 @@ export const requestBodyValue = onlyOAS3((state, path, method) => {
2626
}
2727
)
2828

29+
export const requestBodyInclusionSetting = onlyOAS3((state, path, method) => {
30+
return state.getIn(["requestData", path, method, "bodyInclusion"]) || Map()
31+
}
32+
)
33+
2934
export const activeExamplesMember = onlyOAS3((state, path, method, type, name) => {
3035
return state.getIn(["examples", path, method, type, name, "activeExample"]) || null
3136
}

src/core/plugins/spec/actions.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import serializeError from "serialize-error"
55
import isString from "lodash/isString"
66
import debounce from "lodash/debounce"
77
import set from "lodash/set"
8-
import { isJSONObject, paramToValue } from "core/utils"
8+
import { isJSONObject, paramToValue, isEmptyValue } from "core/utils"
99

1010
// Actions conform to FSA (flux-standard-actions)
1111
// {type: string,payload: Any|Error, meta: obj, error: bool}
@@ -401,11 +401,12 @@ export const executeRequest = (req) =>
401401
req.requestContentType = oas3Selectors.requestContentType(pathName, method)
402402
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
403403
const requestBody = oas3Selectors.requestBodyValue(pathName, method)
404+
const requestBodyInclusionSetting = oas3Selectors.requestBodyInclusionSetting(pathName, method)
404405

405406
if(isJSONObject(requestBody)) {
406407
req.requestBody = JSON.parse(requestBody)
407408
} else if(requestBody && requestBody.toJS) {
408-
req.requestBody = requestBody.toJS()
409+
req.requestBody = requestBody.filter((value, key) => !isEmptyValue(value) || requestBodyInclusionSetting.get(key)).toJS()
409410
} else{
410411
req.requestBody = requestBody
411412
}

src/core/utils.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,3 +947,15 @@ function b64toB64UrlEncoded(str) {
947947
.replace(/\//g, "_")
948948
.replace(/=/g, "")
949949
}
950+
951+
export const isEmptyValue = (value) => {
952+
if (!value) {
953+
return true
954+
}
955+
956+
if (isImmutable(value) && value.isEmpty()) {
957+
return true
958+
}
959+
960+
return false
961+
}

src/style/_table.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ table
146146
}
147147

148148
.parameter__empty_value_toggle {
149+
display: block;
149150
font-size: 13px;
150151
padding-top: 5px;
151152
padding-bottom: 12px;

0 commit comments

Comments
 (0)