351 lines
12 KiB
JavaScript
351 lines
12 KiB
JavaScript
import React from "react"
|
|
import PropTypes from "prop-types"
|
|
import ImPropTypes from "react-immutable-proptypes"
|
|
import { Map, OrderedMap, List, fromJS } from "immutable"
|
|
import { getCommonExtensions, stringify, isEmptyValue, immutableToJS } from "core/utils"
|
|
import { getKnownSyntaxHighlighterLanguage } from "core/utils/jsonParse"
|
|
|
|
/* eslint-disable react/jsx-no-bind */
|
|
|
|
export const getDefaultRequestBodyValue = (requestBody, mediaType, activeExamplesKey, fn) => {
|
|
const mediaTypeValue = requestBody.getIn(["content", mediaType]) ?? OrderedMap()
|
|
const schema = mediaTypeValue.get("schema", OrderedMap()).toJS()
|
|
|
|
const hasExamplesKey = mediaTypeValue.get("examples") !== undefined
|
|
const exampleSchema = mediaTypeValue.get("example")
|
|
const mediaTypeExample = hasExamplesKey
|
|
? mediaTypeValue.getIn([
|
|
"examples",
|
|
activeExamplesKey,
|
|
"value"
|
|
])
|
|
: exampleSchema
|
|
|
|
const exampleValue = fn.getSampleSchema(
|
|
schema,
|
|
mediaType,
|
|
{
|
|
includeWriteOnly: true
|
|
},
|
|
mediaTypeExample
|
|
)
|
|
return stringify(exampleValue)
|
|
}
|
|
|
|
|
|
|
|
const RequestBody = ({
|
|
userHasEditedBody,
|
|
requestBody,
|
|
requestBodyValue,
|
|
requestBodyInclusionSetting,
|
|
requestBodyErrors,
|
|
getComponent,
|
|
getConfigs,
|
|
specSelectors,
|
|
fn,
|
|
contentType,
|
|
isExecute,
|
|
specPath,
|
|
onChange,
|
|
onChangeIncludeEmpty,
|
|
activeExamplesKey,
|
|
updateActiveExamplesKey,
|
|
setRetainRequestBodyValueFlag
|
|
}) => {
|
|
const handleFile = (e) => {
|
|
onChange(e.target.files[0])
|
|
}
|
|
const setIsIncludedOptions = (key) => {
|
|
let options = {
|
|
key,
|
|
shouldDispatchInit: false,
|
|
defaultValue: true
|
|
}
|
|
let currentInclusion = requestBodyInclusionSetting.get(key, "no value")
|
|
if (currentInclusion === "no value") {
|
|
options.shouldDispatchInit = true
|
|
// future: can get/set defaultValue from a config setting
|
|
}
|
|
return options
|
|
}
|
|
|
|
const Markdown = getComponent("Markdown", true)
|
|
const ModelExample = getComponent("modelExample")
|
|
const RequestBodyEditor = getComponent("RequestBodyEditor")
|
|
const HighlightCode = getComponent("HighlightCode", true)
|
|
const ExamplesSelectValueRetainer = getComponent("ExamplesSelectValueRetainer")
|
|
const Example = getComponent("Example")
|
|
const ParameterIncludeEmpty = getComponent("ParameterIncludeEmpty")
|
|
|
|
const { showCommonExtensions } = getConfigs()
|
|
|
|
const requestBodyDescription = requestBody?.get("description") ?? null
|
|
const requestBodyContent = requestBody?.get("content") ?? new OrderedMap()
|
|
contentType = contentType || requestBodyContent.keySeq().first() || ""
|
|
|
|
const mediaTypeValue = requestBodyContent.get(contentType) ?? OrderedMap()
|
|
const schemaForMediaType = mediaTypeValue.get("schema", OrderedMap())
|
|
const rawExamplesOfMediaType = mediaTypeValue.get("examples", null)
|
|
const sampleForMediaType = rawExamplesOfMediaType?.map((container, key) => {
|
|
const val = container?.get("value", null)
|
|
if(val) {
|
|
container = container.set("value", getDefaultRequestBodyValue(
|
|
requestBody,
|
|
contentType,
|
|
key,
|
|
fn,
|
|
), val)
|
|
}
|
|
return container
|
|
})
|
|
|
|
const handleExamplesSelect = (key /*, { isSyntheticChange } */) => {
|
|
updateActiveExamplesKey(key)
|
|
}
|
|
requestBodyErrors = List.isList(requestBodyErrors) ? requestBodyErrors : List()
|
|
|
|
if(!mediaTypeValue.size) {
|
|
return null
|
|
}
|
|
|
|
const isObjectContent = mediaTypeValue.getIn(["schema", "type"]) === "object"
|
|
const isBinaryFormat = mediaTypeValue.getIn(["schema", "format"]) === "binary"
|
|
const isBase64Format = mediaTypeValue.getIn(["schema", "format"]) === "base64"
|
|
|
|
if(
|
|
contentType === "application/octet-stream"
|
|
|| contentType.indexOf("image/") === 0
|
|
|| contentType.indexOf("audio/") === 0
|
|
|| contentType.indexOf("video/") === 0
|
|
|| isBinaryFormat
|
|
|| isBase64Format
|
|
) {
|
|
const Input = getComponent("Input")
|
|
|
|
if(!isExecute) {
|
|
return <i>
|
|
Example values are not available for <code>{contentType}</code> media types.
|
|
</i>
|
|
}
|
|
|
|
return <Input type={"file"} onChange={handleFile} />
|
|
}
|
|
|
|
if (
|
|
isObjectContent &&
|
|
(
|
|
contentType === "application/x-www-form-urlencoded" ||
|
|
contentType.indexOf("multipart/") === 0
|
|
) &&
|
|
schemaForMediaType.get("properties", OrderedMap()).size > 0
|
|
) {
|
|
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
|
const ParameterExt = getComponent("ParameterExt")
|
|
const bodyProperties = schemaForMediaType.get("properties", OrderedMap())
|
|
requestBodyValue = Map.isMap(requestBodyValue) ? requestBodyValue : OrderedMap()
|
|
|
|
return <div className="table-container">
|
|
{ requestBodyDescription &&
|
|
<Markdown source={requestBodyDescription} />
|
|
}
|
|
<table>
|
|
<tbody>
|
|
{
|
|
Map.isMap(bodyProperties) && bodyProperties.entrySeq().map(([key, schema]) => {
|
|
if (schema.get("readOnly")) return
|
|
|
|
const oneOf = schema.get("oneOf")?.get(0)?.toJS()
|
|
const anyOf = schema.get("anyOf")?.get(0)?.toJS()
|
|
schema = fromJS(fn.mergeJsonSchema(schema.toJS(), oneOf ?? anyOf ?? {}))
|
|
|
|
let commonExt = showCommonExtensions ? getCommonExtensions(schema) : null
|
|
const required = schemaForMediaType.get("required", List()).includes(key)
|
|
const typeLabel = fn.jsonSchema202012.getType(immutableToJS(schema))
|
|
const type = fn.jsonSchema202012.foldType(immutableToJS(schema?.get("type")))
|
|
const itemType = fn.jsonSchema202012.foldType(immutableToJS(schema?.getIn(["items", "type"])))
|
|
const format = schema.get("format")
|
|
const description = schema.get("description")
|
|
const currentValue = requestBodyValue.getIn([key, "value"])
|
|
const currentErrors = requestBodyValue.getIn([key, "errors"]) || requestBodyErrors
|
|
const included = requestBodyInclusionSetting.get(key) || false
|
|
|
|
let initialValue = fn.getSampleSchema(schema, false, {
|
|
includeWriteOnly: true
|
|
})
|
|
|
|
if (initialValue === false) {
|
|
initialValue = "false"
|
|
}
|
|
|
|
if (initialValue === 0) {
|
|
initialValue = "0"
|
|
}
|
|
|
|
if (typeof initialValue !== "string" && type === "object") {
|
|
initialValue = stringify(initialValue)
|
|
}
|
|
|
|
if (typeof initialValue === "string" && type === "array") {
|
|
initialValue = JSON.parse(initialValue)
|
|
}
|
|
|
|
const isFile = type === "string" && (format === "binary" || format === "base64")
|
|
|
|
const jsonSchemaForm = <JsonSchemaForm
|
|
fn={fn}
|
|
dispatchInitialValue={!isFile}
|
|
schema={schema}
|
|
description={key}
|
|
getComponent={getComponent}
|
|
value={currentValue === undefined ? initialValue : currentValue}
|
|
required={required}
|
|
errors={currentErrors}
|
|
onChange={(value) => {
|
|
onChange(value, [key])
|
|
}}
|
|
/>
|
|
|
|
return <tr key={key} className="parameters" data-property-name={key}>
|
|
<td className="parameters-col_name">
|
|
<div className={required ? "parameter__name required" : "parameter__name"}>
|
|
{ key }
|
|
{ !required ? null : <span> *</span> }
|
|
</div>
|
|
<div className="parameter__type">
|
|
{ typeLabel }
|
|
{ format && <span className="prop-format">(${format})</span>}
|
|
{!showCommonExtensions || !commonExt.size ? null : commonExt.entrySeq().map(([key, v]) => <ParameterExt key={`${key}-${v}`} xKey={key} xVal={v} />)}
|
|
</div>
|
|
<div className="parameter__deprecated">
|
|
{ schema.get("deprecated") ? "deprecated": null }
|
|
</div>
|
|
</td>
|
|
<td className="parameters-col_description">
|
|
<Markdown source={ description }></Markdown>
|
|
{isExecute ? <div>
|
|
{(type === "object" || itemType === "object") ? (
|
|
<ModelExample
|
|
getComponent={getComponent}
|
|
specPath={specPath.push("schema")}
|
|
getConfigs={getConfigs}
|
|
isExecute={isExecute}
|
|
specSelectors={specSelectors}
|
|
schema={schema}
|
|
example={jsonSchemaForm}
|
|
/>
|
|
) : jsonSchemaForm
|
|
}
|
|
{required ? null : (
|
|
<ParameterIncludeEmpty
|
|
onChange={(value) => onChangeIncludeEmpty(key, value)}
|
|
isIncluded={included}
|
|
isIncludedOptions={setIsIncludedOptions(key)}
|
|
isDisabled={Array.isArray(currentValue) ? currentValue.length !== 0 : !isEmptyValue(currentValue)}
|
|
/>
|
|
)}
|
|
</div> : null }
|
|
</td>
|
|
</tr>
|
|
})
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
const sampleRequestBody = getDefaultRequestBodyValue(
|
|
requestBody,
|
|
contentType,
|
|
activeExamplesKey,
|
|
fn,
|
|
)
|
|
let language = null
|
|
let testValueForJson = getKnownSyntaxHighlighterLanguage(sampleRequestBody)
|
|
if (testValueForJson) {
|
|
language = "json"
|
|
}
|
|
|
|
return <div>
|
|
{ requestBodyDescription &&
|
|
<Markdown source={requestBodyDescription} />
|
|
}
|
|
{
|
|
sampleForMediaType ? (
|
|
<ExamplesSelectValueRetainer
|
|
userHasEditedBody={userHasEditedBody}
|
|
examples={sampleForMediaType}
|
|
currentKey={activeExamplesKey}
|
|
currentUserInputValue={requestBodyValue}
|
|
onSelect={handleExamplesSelect}
|
|
updateValue={onChange}
|
|
defaultToFirstExample={true}
|
|
getComponent={getComponent}
|
|
setRetainRequestBodyValueFlag={setRetainRequestBodyValueFlag}
|
|
/>
|
|
) : null
|
|
}
|
|
{
|
|
isExecute ? (
|
|
<div>
|
|
<RequestBodyEditor
|
|
value={requestBodyValue}
|
|
errors={requestBodyErrors}
|
|
defaultValue={sampleRequestBody}
|
|
onChange={onChange}
|
|
getComponent={getComponent}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<ModelExample
|
|
getComponent={ getComponent }
|
|
getConfigs={ getConfigs }
|
|
specSelectors={ specSelectors }
|
|
expandDepth={1}
|
|
isExecute={isExecute}
|
|
schema={mediaTypeValue.get("schema")}
|
|
specPath={specPath.push("content", contentType)}
|
|
example={
|
|
<HighlightCode className="body-param__example" language={language}>
|
|
{stringify(requestBodyValue) || sampleRequestBody}
|
|
</HighlightCode>
|
|
}
|
|
includeWriteOnly={true}
|
|
/>
|
|
)
|
|
}
|
|
{
|
|
sampleForMediaType ? (
|
|
<Example
|
|
example={sampleForMediaType.get(activeExamplesKey)}
|
|
getComponent={getComponent}
|
|
getConfigs={getConfigs}
|
|
/>
|
|
) : null
|
|
}
|
|
</div>
|
|
}
|
|
|
|
RequestBody.propTypes = {
|
|
userHasEditedBody: PropTypes.bool.isRequired,
|
|
requestBody: ImPropTypes.orderedMap.isRequired,
|
|
requestBodyValue: ImPropTypes.orderedMap.isRequired,
|
|
requestBodyInclusionSetting: ImPropTypes.map.isRequired,
|
|
requestBodyErrors: ImPropTypes.list.isRequired,
|
|
getComponent: PropTypes.func.isRequired,
|
|
getConfigs: PropTypes.func.isRequired,
|
|
fn: PropTypes.object.isRequired,
|
|
specSelectors: PropTypes.object.isRequired,
|
|
contentType: PropTypes.string,
|
|
isExecute: PropTypes.bool.isRequired,
|
|
onChange: PropTypes.func.isRequired,
|
|
onChangeIncludeEmpty: PropTypes.func.isRequired,
|
|
specPath: PropTypes.array.isRequired,
|
|
activeExamplesKey: PropTypes.string,
|
|
updateActiveExamplesKey: PropTypes.func,
|
|
setRetainRequestBodyValueFlag: PropTypes.func,
|
|
oas3Actions: PropTypes.object.isRequired
|
|
}
|
|
|
|
export default RequestBody
|