Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allowEmptyValue controls #4788

Merged
merged 13 commits into from
Aug 4, 2018
27 changes: 27 additions & 0 deletions src/core/components/parameter-include-empty.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react"
import cx from "classnames"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"

export const ParameterIncludeEmpty = ({ param, isIncluded, onChange, isDisabled }) => {
const onCheckboxChange = e => {
onChange(e.target.checked)
}
if(!param.get("allowEmptyValue")) {
return null
}
return <div className={cx("parameter__empty_value_toggle", {
"disabled": isDisabled
})}>
<input type="checkbox" disabled={isDisabled} checked={!isDisabled && isIncluded} onChange={onCheckboxChange} />
Send empty value
</div>
}
ParameterIncludeEmpty.propTypes = {
param: ImPropTypes.map.isRequired,
isIncluded: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
}

export default ParameterIncludeEmpty
30 changes: 29 additions & 1 deletion src/core/components/parameter-row.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default class ParameterRow extends Component {
isExecute: PropTypes.bool,
onChangeConsumes: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
getConfigs: PropTypes.func.isRequired,
specPath: ImPropTypes.list.isRequired
Expand Down Expand Up @@ -61,7 +62,23 @@ export default class ParameterRow extends Component {

onChangeWrapper = (value, isXml = false) => {
let { onChange, rawParam } = this.props
return onChange(rawParam, value, isXml)
let valueForUpstream

// Coerce empty strings and empty Immutable objects to null
if(value === "" || (value && value.size === 0)) {
valueForUpstream = null
} else {
valueForUpstream = value
}

return onChange(rawParam, valueForUpstream, isXml)
}

onChangeIncludeEmpty = (newValue) => {
let { specActions, param, pathMethod } = this.props
const paramName = param.get("name")
const paramIn = param.get("in")
return specActions.updateEmptyParamInclusion(pathMethod, paramName, paramIn, newValue)
}

setDefaultValue = () => {
Expand Down Expand Up @@ -120,6 +137,7 @@ export default class ParameterRow extends Component {
const ModelExample = getComponent("modelExample")
const Markdown = getComponent("Markdown")
const ParameterExt = getComponent("ParameterExt")
const ParameterIncludeEmpty = getComponent("ParameterIncludeEmpty")

let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
let format = param.get("format")
Expand Down Expand Up @@ -225,6 +243,16 @@ export default class ParameterRow extends Component {
: null
}

{
!bodyParam && isExecute ?
<ParameterIncludeEmpty
onChange={this.onChangeIncludeEmpty}
isIncluded={specSelectors.parameterInclusionSettingFor(pathMethod, param.get("name"), param.get("in"))}
isDisabled={value && value.size !== 0}
param={param} />
: null
}

</td>

</tr>
Expand Down
4 changes: 3 additions & 1 deletion src/core/components/parameters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ export default class Parameters extends Component {
fn,
getComponent,
getConfigs,
specSelectors,
specSelectors,
specActions,
pathMethod
} = this.props

Expand Down Expand Up @@ -107,6 +108,7 @@ export default class Parameters extends Component {
onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper}
specSelectors={ specSelectors }
specActions={specActions}
pathMethod={ pathMethod }
isExecute={ isExecute }/>
)).toArray()
Expand Down
2 changes: 2 additions & 0 deletions src/core/plugins/oas3/wrap-components/parameters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Parameters extends Component {
getComponent,
getConfigs,
specSelectors,
specActions,
oas3Actions,
oas3Selectors,
pathMethod,
Expand Down Expand Up @@ -151,6 +152,7 @@ class Parameters extends Component {
onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper}
specSelectors={ specSelectors }
specActions={ specActions }
pathMethod={ pathMethod }
isExecute={ isExecute }/>
)).toArray()
Expand Down
34 changes: 34 additions & 0 deletions src/core/plugins/spec/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const UPDATE_SPEC = "spec_update_spec"
export const UPDATE_URL = "spec_update_url"
export const UPDATE_JSON = "spec_update_json"
export const UPDATE_PARAM = "spec_update_param"
export const UPDATE_EMPTY_PARAM_INCLUSION = "spec_update_empty_param_inclusion"
export const VALIDATE_PARAMS = "spec_validate_param"
export const SET_RESPONSE = "spec_set_response"
export const SET_REQUEST = "spec_set_request"
Expand Down Expand Up @@ -270,6 +271,18 @@ export const validateParams = ( payload, isOAS3 ) =>{
}
}

export const updateEmptyParamInclusion = ( pathMethod, paramName, paramIn, includeEmptyValue ) =>{
return {
type: UPDATE_EMPTY_PARAM_INCLUSION,
payload:{
pathMethod,
paramName,
paramIn,
includeEmptyValue
}
}
}

export function clearValidateParams( payload ){
return {
type: CLEAR_VALIDATE_PARAMS,
Expand Down Expand Up @@ -327,7 +340,28 @@ export const executeRequest = (req) =>
let { pathName, method, operation } = req
let { requestInterceptor, responseInterceptor } = getConfigs()


let op = operation.toJS()

// ensure that explicitly-included params are in the request

if(op && op.parameters && op.parameters.length) {
op.parameters
.filter(param => param && param.allowEmptyValue === true)
.forEach(param => {
if (specSelectors.parameterInclusionSettingFor([pathName, method], param.name, param.in)) {
req.parameters = req.parameters || {}
const paramValue = req.parameters[param.name]

// if the value is falsy or an empty Immutable iterable...
if(!paramValue || (paramValue && paramValue.size === 0)) {
// set it to empty string, so Swagger Client will treat it as
// present but empty.
req.parameters[param.name] = ""
}
}
})
}

// if url is relative, parseUrl makes it absolute by inferring from `window.location`
req.contextUrl = parseUrl(specSelectors.url()).toString()
Expand Down
17 changes: 17 additions & 0 deletions src/core/plugins/spec/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
UPDATE_URL,
UPDATE_JSON,
UPDATE_PARAM,
UPDATE_EMPTY_PARAM_INCLUSION,
VALIDATE_PARAMS,
SET_RESPONSE,
SET_REQUEST,
Expand Down Expand Up @@ -70,6 +71,22 @@ export default {
)
},

[UPDATE_EMPTY_PARAM_INCLUSION]: ( state, {payload} ) => {
let { pathMethod, paramName, paramIn, includeEmptyValue } = payload

if(!paramName || !paramIn) {
console.warn("Warning: UPDATE_EMPTY_PARAM_INCLUSION could not generate a paramKey.")
return state
}

const paramKey = `${paramName}.${paramIn}`

return state.setIn(
["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey],
includeEmptyValue
)
},

[VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
let meta = state.getIn( [ "meta", "paths", ...pathMethod ], fromJS({}) )
let isXml = /xml/i.test(meta.get("consumes_value"))
Expand Down
5 changes: 5 additions & 0 deletions src/core/plugins/spec/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ export const parameterWithMetaByIdentity = (state, pathMethod, param) => {
return mergedParams.find(curr => curr.get("in") === param.get("in") && curr.get("name") === param.get("name"), OrderedMap())
}

export const parameterInclusionSettingFor = (state, pathMethod, paramName, paramIn) => {
const paramKey = `${paramName}.${paramIn}`
return state.getIn(["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey], false)
}


export const parameterWithMeta = (state, pathMethod, paramName, paramIn) => {
const opParams = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "parameters"], OrderedMap())
Expand Down
2 changes: 2 additions & 0 deletions src/core/presets/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import Response from "core/components/response"
import ResponseBody from "core/components/response-body"
import Parameters from "core/components/parameters"
import ParameterExt from "core/components/parameter-extension"
import ParameterIncludeEmpty from "core/components/parameter-include-empty"
import ParameterRow from "core/components/parameter-row"
import Execute from "core/components/execute"
import Headers from "core/components/headers"
Expand Down Expand Up @@ -143,6 +144,7 @@ export default function() {
OperationExt,
OperationExtRow,
ParameterExt,
ParameterIncludeEmpty,
OperationTag,
OperationContainer,
DeepLink,
Expand Down
14 changes: 14 additions & 0 deletions src/style/_table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ table
@include text_code($table-parameter-deprecated-font-color);
}

.parameter__empty_value_toggle {
font-size: 13px;
padding-top: 5px;
padding-bottom: 12px;

input {
margin-right: 7px;
}

&.disabled {
opacity: 0.7;
}
}


.table-container
{
Expand Down
20 changes: 19 additions & 1 deletion test/core/plugins/spec/actions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import { fromJS } from "immutable"
import { execute, executeRequest, changeParamByIdentity } from "corePlugins/spec/actions"
import { execute, executeRequest, changeParamByIdentity, updateEmptyParamInclusion } from "corePlugins/spec/actions"

describe("spec plugin - actions", function(){

Expand Down Expand Up @@ -207,4 +207,22 @@ describe("spec plugin - actions", function(){
})
})
})

describe("updateEmptyParamInclusion", function () {
it("should map its arguments to a payload", function () {
const pathMethod = ["/one", "get"]

const result = updateEmptyParamInclusion(pathMethod, "param", "query", true)

expect(result).toEqual({
type: "spec_update_empty_param_inclusion",
payload: {
pathMethod,
paramName: "param",
paramIn: "query",
includeEmptyValue: true
}
})
})
})
})
22 changes: 22 additions & 0 deletions test/core/plugins/spec/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,26 @@ describe("spec plugin - reducer", function(){
expect(value).toEqual(`{ "a": 123 }`)
})
})
describe("SPEC_UPDATE_EMPTY_PARAM_INCLUSION", function() {
it("should store parameter values by name+in", () => {
const updateParam = reducer["spec_update_empty_param_inclusion"]

const path = "/pet/post"
const method = "POST"

const state = fromJS({})

const result = updateParam(state, {
payload: {
pathMethod: [path, method],
paramName: "param",
paramIn: "query",
includeEmptyValue: true
}
})

const response = result.getIn(["meta", "paths", path, method, "parameter_inclusions", "param.query"])
expect(response).toEqual(true)
})
})
})
41 changes: 40 additions & 1 deletion test/core/plugins/spec/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import Petstore from "./assets/petstore.json"
import {
operationWithMeta,
parameterWithMeta,
parameterWithMetaByIdentity
parameterWithMetaByIdentity,
parameterInclusionSettingFor
} from "../../../../src/core/plugins/spec/selectors"

describe("spec plugin - selectors", function(){
Expand Down Expand Up @@ -712,4 +713,42 @@ describe("spec plugin - selectors", function(){
})
})
})
describe("parameterInclusionSettingFor", function() {
it("should support getting name+in param inclusion settings", function () {
const param = fromJS({
name: "param",
in: "query",
allowEmptyValue: true
})

const state = fromJS({
json: {
paths: {
"/": {
"get": {
parameters: [
param
]
}
}
}
},
meta: {
paths: {
"/": {
"get": {
"parameter_inclusions": {
[`param.query`]: true
}
}
}
}
}
})

const result = parameterInclusionSettingFor(state, ["/", "get"], "param", "query")

expect(result).toEqual(true)
})
})
})
Loading