feat: request snippets plugin (#6910)
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import curlify from "core/curlify"
|
||||
import { CopyToClipboard } from "react-copy-to-clipboard"
|
||||
import {SyntaxHighlighter, getStyle} from "core/syntax-highlighting"
|
||||
import get from "lodash/get"
|
||||
import { requestSnippetGenerator_curl_bash } from "../plugins/request-snippets/fn"
|
||||
|
||||
export default class Curl extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -13,7 +13,7 @@ export default class Curl extends React.Component {
|
||||
|
||||
render() {
|
||||
let { request, getConfigs } = this.props
|
||||
let curl = curlify(request)
|
||||
let curl = requestSnippetGenerator_curl_bash(request)
|
||||
|
||||
const config = getConfigs()
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export default class LiveResponse extends React.Component {
|
||||
|
||||
render() {
|
||||
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, path, method } = this.props
|
||||
const { showMutatedRequest } = getConfigs()
|
||||
const { showMutatedRequest, requestSnippetsEnabled } = getConfigs()
|
||||
|
||||
const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(path, method) : specSelectors.requestFor(path, method)
|
||||
const status = response.get("status")
|
||||
@@ -62,7 +62,6 @@ export default class LiveResponse extends React.Component {
|
||||
const headersKeys = Object.keys(headers)
|
||||
const contentType = headers["content-type"] || headers["Content-Type"]
|
||||
|
||||
const Curl = getComponent("curl")
|
||||
const ResponseBody = getComponent("responseBody")
|
||||
const returnObject = headersKeys.map(key => {
|
||||
var joinedHeaders = Array.isArray(headers[key]) ? headers[key].join() : headers[key]
|
||||
@@ -70,10 +69,14 @@ export default class LiveResponse extends React.Component {
|
||||
})
|
||||
const hasHeaders = returnObject.length !== 0
|
||||
const Markdown = getComponent("Markdown", true)
|
||||
const RequestSnippets = getComponent("RequestSnippets", true)
|
||||
const Curl = getComponent("curl")
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ curlRequest && <Curl request={ curlRequest } getConfigs={ getConfigs } /> }
|
||||
{ curlRequest && (requestSnippetsEnabled === true || requestSnippetsEnabled === "true"
|
||||
? <RequestSnippets request={ curlRequest }/>
|
||||
: <Curl request={ curlRequest } getConfigs={ getConfigs } />) }
|
||||
{ url && <div>
|
||||
<h4>Request URL</h4>
|
||||
<div className="request-url">
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import win from "./window"
|
||||
import { Map } from "immutable"
|
||||
|
||||
/**
|
||||
* if duplicate key name existed from FormData entries,
|
||||
* we mutated the key name by appending a hashIdx
|
||||
* @param {String} k - possibly mutated key name
|
||||
* @return {String} - src key name
|
||||
*/
|
||||
const extractKey = (k) => {
|
||||
const hashIdx = "_**[]"
|
||||
if (k.indexOf(hashIdx) < 0) {
|
||||
return k
|
||||
}
|
||||
return k.split(hashIdx)[0].trim()
|
||||
}
|
||||
|
||||
export default function curl( request ){
|
||||
let curlified = []
|
||||
let isMultipartFormDataRequest = false
|
||||
let headers = request.get("headers")
|
||||
curlified.push( "curl" )
|
||||
|
||||
if (request.get("curlOptions")) {
|
||||
curlified.push(...request.get("curlOptions"))
|
||||
}
|
||||
|
||||
curlified.push( "-X", request.get("method") )
|
||||
curlified.push( `"${request.get("url")}"`)
|
||||
|
||||
if ( headers && headers.size ) {
|
||||
for( let p of request.get("headers").entries() ){
|
||||
let [ h,v ] = p
|
||||
curlified.push( "-H " )
|
||||
curlified.push( `"${h}: ${v.replace(/\$/g, "\\$")}"` )
|
||||
isMultipartFormDataRequest = isMultipartFormDataRequest || /^content-type$/i.test(h) && /^multipart\/form-data$/i.test(v)
|
||||
}
|
||||
}
|
||||
|
||||
if ( request.get("body") ){
|
||||
if (isMultipartFormDataRequest && ["POST", "PUT", "PATCH"].includes(request.get("method"))) {
|
||||
for( let [ k,v ] of request.get("body").entrySeq()) {
|
||||
let extractedKey = extractKey(k)
|
||||
curlified.push( "-F" )
|
||||
if (v instanceof win.File) {
|
||||
curlified.push(`"${extractedKey}=@${v.name}${v.type ? `;type=${v.type}` : ""}"` )
|
||||
} else {
|
||||
curlified.push(`"${extractedKey}=${v}"` )
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curlified.push( "-d" )
|
||||
let reqBody = request.get("body")
|
||||
if (!Map.isMap(reqBody)) {
|
||||
curlified.push( JSON.stringify( request.get("body") ).replace(/\\n/g, "").replace(/\$/g, "\\$") )
|
||||
} else {
|
||||
let curlifyToJoin = []
|
||||
for (let [k, v] of request.get("body").entrySeq()) {
|
||||
let extractedKey = extractKey(k)
|
||||
if (v instanceof win.File) {
|
||||
curlifyToJoin.push(`"${extractedKey}":{"name":"${v.name}"${v.type ? `,"type":"${v.type}"` : ""}}`)
|
||||
} else {
|
||||
curlifyToJoin.push(`"${extractedKey}":${JSON.stringify(v).replace(/\\n/g, "").replace("$", "\\$")}`)
|
||||
}
|
||||
}
|
||||
curlified.push(`{${curlifyToJoin.join()}}`)
|
||||
}
|
||||
}
|
||||
} else if(!request.get("body") && request.get("method") === "POST") {
|
||||
curlified.push( "-d" )
|
||||
curlified.push( "\"\"" )
|
||||
}
|
||||
|
||||
return curlified.join( " " )
|
||||
}
|
||||
@@ -53,6 +53,29 @@ export default function SwaggerUI(opts) {
|
||||
showExtensions: false,
|
||||
showCommonExtensions: false,
|
||||
withCredentials: undefined,
|
||||
requestSnippetsEnabled: false,
|
||||
requestSnippets: {
|
||||
generators: {
|
||||
"curl_bash": {
|
||||
title: "cURL (bash)",
|
||||
syntax: "bash"
|
||||
},
|
||||
"curl_powershell": {
|
||||
title: "cURL (PowerShell)",
|
||||
syntax: "powershell"
|
||||
},
|
||||
"curl_cmd": {
|
||||
title: "cURL (CMD)",
|
||||
syntax: "bash"
|
||||
},
|
||||
"node_native": {
|
||||
title: "Node.js (Native)",
|
||||
syntax: "javascript"
|
||||
},
|
||||
},
|
||||
defaultExpanded: true,
|
||||
languagesMask: null, // e.g. only show curl bash = ["curl_bash"]
|
||||
},
|
||||
supportedSubmitMethods: [
|
||||
"get",
|
||||
"put",
|
||||
@@ -107,7 +130,8 @@ export default function SwaggerUI(opts) {
|
||||
spec: {
|
||||
spec: "",
|
||||
url: constructorConfig.url
|
||||
}
|
||||
},
|
||||
requestSnippets: constructorConfig.requestSnippets
|
||||
}, constructorConfig.initialState)
|
||||
}
|
||||
|
||||
|
||||
217
src/core/plugins/request-snippets/fn.js
Normal file
217
src/core/plugins/request-snippets/fn.js
Normal file
@@ -0,0 +1,217 @@
|
||||
import win from "../../window"
|
||||
import { Map } from "immutable"
|
||||
import Url from "url-parse"
|
||||
|
||||
/**
|
||||
* if duplicate key name existed from FormData entries,
|
||||
* we mutated the key name by appending a hashIdx
|
||||
* @param {String} k - possibly mutated key name
|
||||
* @return {String} - src key name
|
||||
*/
|
||||
const extractKey = (k) => {
|
||||
const hashIdx = "_**[]"
|
||||
if (k.indexOf(hashIdx) < 0) {
|
||||
return k
|
||||
}
|
||||
return k.split(hashIdx)[0].trim()
|
||||
}
|
||||
|
||||
const escapeShell = (str) => {
|
||||
if (str === "-d ") {
|
||||
return str
|
||||
}
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
if (!/^[_\/-]/g.test(str))
|
||||
return ("'" + str
|
||||
.replace(/'/g, "'\\''") + "'")
|
||||
else
|
||||
return str
|
||||
}
|
||||
|
||||
const escapeCMD = (str) => {
|
||||
str = str
|
||||
.replace(/\^/g, "^^")
|
||||
.replace(/\\"/g, "\\\\\"")
|
||||
.replace(/"/g, "\"\"")
|
||||
.replace(/\n/g, "^\n")
|
||||
if (str === "-d ") {
|
||||
return str
|
||||
.replace(/-d /g, "-d ^\n")
|
||||
}
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
if (!/^[_\/-]/g.test(str))
|
||||
return "\"" + str + "\""
|
||||
else
|
||||
return str
|
||||
}
|
||||
|
||||
const escapePowershell = (str) => {
|
||||
if (str === "-d ") {
|
||||
return str
|
||||
}
|
||||
if (/\n/.test(str)) {
|
||||
return "@\"\n" + str.replace(/"/g, "\\\"").replace(/`/g, "``").replace(/\$/, "`$") + "\n\"@"
|
||||
}
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
if (!/^[_\/-]/g.test(str))
|
||||
return "'" + str
|
||||
.replace(/"/g, "\"\"")
|
||||
.replace(/'/g, "''") + "'"
|
||||
else
|
||||
return str
|
||||
}
|
||||
|
||||
function getStringBodyOfMap(request) {
|
||||
let curlifyToJoin = []
|
||||
for (let [k, v] of request.get("body").entrySeq()) {
|
||||
let extractedKey = extractKey(k)
|
||||
if (v instanceof win.File) {
|
||||
curlifyToJoin.push(` "${extractedKey}": {\n "name": "${v.name}"${v.type ? `,\n "type": "${v.type}"` : ""}\n }`)
|
||||
} else {
|
||||
curlifyToJoin.push(` "${extractedKey}": ${JSON.stringify(v, null, 2).replace(/(\r\n|\r|\n)/g, "\n ")}`)
|
||||
}
|
||||
}
|
||||
return `{\n${curlifyToJoin.join(",\n")}\n}`
|
||||
}
|
||||
|
||||
const curlify = (request, escape, newLine, ext = "") => {
|
||||
let isMultipartFormDataRequest = false
|
||||
let curlified = ""
|
||||
const addWords = (...args) => curlified += " " + args.map(escape).join(" ")
|
||||
const addWordsWithoutLeadingSpace = (...args) => curlified += args.map(escape).join(" ")
|
||||
const addNewLine = () => curlified += ` ${newLine}`
|
||||
const addIndent = (level = 1) => curlified += " ".repeat(level)
|
||||
let headers = request.get("headers")
|
||||
curlified += "curl" + ext
|
||||
|
||||
if (request.has("curlOptions")) {
|
||||
addWords(...request.get("curlOptions"))
|
||||
}
|
||||
|
||||
addWords("-X", request.get("method"))
|
||||
|
||||
addNewLine()
|
||||
addIndent()
|
||||
addWordsWithoutLeadingSpace(`${request.get("url")}`)
|
||||
|
||||
if (headers && headers.size) {
|
||||
for (let p of request.get("headers").entries()) {
|
||||
addNewLine()
|
||||
addIndent()
|
||||
let [h, v] = p
|
||||
addWordsWithoutLeadingSpace("-H", `${h}: ${v}`)
|
||||
isMultipartFormDataRequest = isMultipartFormDataRequest || /^content-type$/i.test(h) && /^multipart\/form-data$/i.test(v)
|
||||
}
|
||||
}
|
||||
|
||||
if (request.get("body")) {
|
||||
if (isMultipartFormDataRequest && ["POST", "PUT", "PATCH"].includes(request.get("method"))) {
|
||||
for (let [k, v] of request.get("body").entrySeq()) {
|
||||
let extractedKey = extractKey(k)
|
||||
addNewLine()
|
||||
addIndent()
|
||||
addWordsWithoutLeadingSpace("-F")
|
||||
if (v instanceof win.File) {
|
||||
addWords(`${extractedKey}=@${v.name}${v.type ? `;type=${v.type}` : ""}`)
|
||||
} else {
|
||||
addWords(`${extractedKey}=${v}`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addNewLine()
|
||||
addIndent()
|
||||
addWordsWithoutLeadingSpace("-d ")
|
||||
let reqBody = request.get("body")
|
||||
if (!Map.isMap(reqBody)) {
|
||||
if (typeof reqBody !== "string") {
|
||||
reqBody = JSON.stringify(reqBody)
|
||||
}
|
||||
addWordsWithoutLeadingSpace(reqBody)
|
||||
} else {
|
||||
addWordsWithoutLeadingSpace(getStringBodyOfMap(request))
|
||||
}
|
||||
}
|
||||
} else if (!request.get("body") && request.get("method") === "POST") {
|
||||
addNewLine()
|
||||
addIndent()
|
||||
addWordsWithoutLeadingSpace("-d ''")
|
||||
}
|
||||
|
||||
return curlified
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export const requestSnippetGenerator_curl_powershell = (request) => {
|
||||
return curlify(request, escapePowershell, "`\n", ".exe")
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export const requestSnippetGenerator_curl_bash = (request) => {
|
||||
return curlify(request, escapeShell, "\\\n")
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export const requestSnippetGenerator_curl_cmd = (request) => {
|
||||
return curlify(request, escapeCMD, "^\n")
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export const requestSnippetGenerator_node_native = (request) => {
|
||||
const url = new Url(request.get("url"))
|
||||
let isMultipartFormDataRequest = false
|
||||
const headers = request.get("headers")
|
||||
if(headers && headers.size) {
|
||||
request.get("headers").map((val, key) => {
|
||||
isMultipartFormDataRequest = isMultipartFormDataRequest || /^content-type$/i.test(key) && /^multipart\/form-data$/i.test(val)
|
||||
})
|
||||
}
|
||||
const packageStr = url.protocol === "https:" ? "https" : "http"
|
||||
let reqBody = request.get("body")
|
||||
if (request.get("body")) {
|
||||
if (isMultipartFormDataRequest && ["POST", "PUT", "PATCH"].includes(request.get("method"))) {
|
||||
return "throw new Error(\"Currently unsupported content-type: /^multipart\\/form-data$/i\");"
|
||||
} else {
|
||||
if (!Map.isMap(reqBody)) {
|
||||
if (typeof reqBody !== "string") {
|
||||
reqBody = JSON.stringify(reqBody)
|
||||
}
|
||||
} else {
|
||||
reqBody = getStringBodyOfMap(request)
|
||||
}
|
||||
}
|
||||
} else if (!request.get("body") && request.get("method") === "POST") {
|
||||
reqBody = ""
|
||||
}
|
||||
|
||||
const stringBody = "`" + (reqBody || "")
|
||||
.replace(/\\n/g, "\n")
|
||||
.replace(/`/g, "\\`")
|
||||
+ "`"
|
||||
|
||||
return `const http = require("${packageStr}");
|
||||
|
||||
const options = {
|
||||
"method": "${request.get("method")}",
|
||||
"hostname": "${url.host}",
|
||||
"port": ${url.port || "null"},
|
||||
"path": "${url.pathname}"${headers && headers.size ? `,
|
||||
"headers": {
|
||||
${request.get("headers").map((val, key) => `"${key}": "${val}"`).valueSeq().join(",\n ")}
|
||||
}` : ""}
|
||||
};
|
||||
|
||||
const req = http.request(options, function (res) {
|
||||
const chunks = [];
|
||||
|
||||
res.on("data", function (chunk) {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
res.on("end", function () {
|
||||
const body = Buffer.concat(chunks);
|
||||
console.log(body.toString());
|
||||
});
|
||||
});
|
||||
${reqBody ? `\nreq.write(${stringBody});` : ""}
|
||||
req.end();`
|
||||
}
|
||||
16
src/core/plugins/request-snippets/index.js
Normal file
16
src/core/plugins/request-snippets/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import * as fn from "./fn"
|
||||
import * as selectors from "./selectors"
|
||||
import { RequestSnippets } from "./request-snippets"
|
||||
export default () => {
|
||||
return {
|
||||
components: {
|
||||
RequestSnippets
|
||||
},
|
||||
fn,
|
||||
statePlugins: {
|
||||
requestSnippets: {
|
||||
selectors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/core/plugins/request-snippets/request-snippets.jsx
Normal file
127
src/core/plugins/request-snippets/request-snippets.jsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import React from "react"
|
||||
import { CopyToClipboard } from "react-copy-to-clipboard"
|
||||
import PropTypes from "prop-types"
|
||||
import get from "lodash/get"
|
||||
import {SyntaxHighlighter, getStyle} from "core/syntax-highlighting"
|
||||
|
||||
export class RequestSnippets extends React.Component {
|
||||
constructor() {
|
||||
super()
|
||||
this.state = {
|
||||
activeLanguage: this.props?.requestSnippetsSelectors?.getSnippetGenerators()?.keySeq().first(),
|
||||
expanded: this.props?.requestSnippetsSelectors?.getDefaultExpanded(),
|
||||
}
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
request: PropTypes.object.isRequired,
|
||||
requestSnippetsSelectors: PropTypes.object.isRequired,
|
||||
getConfigs: PropTypes.object.isRequired,
|
||||
requestSnippetsActions: PropTypes.object.isRequired,
|
||||
}
|
||||
render() {
|
||||
const {request, getConfigs, requestSnippetsSelectors } = this.props
|
||||
const snippetGenerators = requestSnippetsSelectors.getSnippetGenerators()
|
||||
const activeLanguage = this.state.activeLanguage || snippetGenerators.keySeq().first()
|
||||
const activeGenerator = snippetGenerators.get(activeLanguage)
|
||||
const snippet = activeGenerator.get("fn")(request)
|
||||
const onGenChange = (key) => {
|
||||
const needsChange = activeLanguage !== key
|
||||
if(needsChange) {
|
||||
this.setState({
|
||||
activeLanguage: key
|
||||
})
|
||||
}
|
||||
}
|
||||
const style = {
|
||||
cursor: "pointer",
|
||||
lineHeight: 1,
|
||||
display: "inline-flex",
|
||||
backgroundColor: "rgb(250, 250, 250)",
|
||||
paddingBottom: "0",
|
||||
paddingTop: "0",
|
||||
border: "1px solid rgb(51, 51, 51)",
|
||||
borderRadius: "4px 4px 0 0",
|
||||
boxShadow: "none",
|
||||
borderBottom: "none"
|
||||
}
|
||||
const activeStyle = {
|
||||
cursor: "pointer",
|
||||
lineHeight: 1,
|
||||
display: "inline-flex",
|
||||
backgroundColor: "rgb(51, 51, 51)",
|
||||
boxShadow: "none",
|
||||
border: "1px solid rgb(51, 51, 51)",
|
||||
paddingBottom: "0",
|
||||
paddingTop: "0",
|
||||
borderRadius: "4px 4px 0 0",
|
||||
marginTop: "-5px",
|
||||
marginRight: "-5px",
|
||||
marginLeft: "-5px",
|
||||
zIndex: "9999",
|
||||
borderBottom: "none"
|
||||
}
|
||||
const getBtnStyle = (key) => {
|
||||
if (key === activeLanguage) {
|
||||
return activeStyle
|
||||
}
|
||||
return style
|
||||
}
|
||||
const config = getConfigs()
|
||||
|
||||
const SnippetComponent = config?.syntaxHighlight?.activated
|
||||
? <SyntaxHighlighter
|
||||
language={activeGenerator.get("syntax")}
|
||||
className="curl microlight"
|
||||
onWheel={function(e) {return this.preventYScrollingBeyondElement(e)}}
|
||||
style={getStyle(get(config, "syntaxHighlight.theme"))}
|
||||
>
|
||||
{snippet}
|
||||
</SyntaxHighlighter>
|
||||
:
|
||||
<textarea readOnly={true} className="curl" value={snippet}></textarea>
|
||||
|
||||
const expanded = this.state.expanded === undefined ? this.props?.requestSnippetsSelectors?.getDefaultExpanded() : this.state.expanded
|
||||
return (
|
||||
<div>
|
||||
<div style={{width: "100%", display: "flex", justifyContent: "flex-start", alignItems: "center", marginBottom: "15px"}}>
|
||||
<h4
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => this.setState({expanded: !expanded})}
|
||||
>Snippets</h4>
|
||||
<button
|
||||
onClick={() => this.setState({expanded: !expanded})}
|
||||
style={{ border: "none", background: "none" }}
|
||||
title={expanded ? "Collapse operation": "Expand operation"}
|
||||
>
|
||||
<svg className="arrow" width="10" height="10">
|
||||
<use href={expanded ? "#large-arrow-down" : "#large-arrow"} xlinkHref={expanded ? "#large-arrow-down" : "#large-arrow"} />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{
|
||||
expanded && <div className="curl-command">
|
||||
<div style={{paddingLeft: "15px", paddingRight: "10px", width: "100%", display: "flex"}}>
|
||||
{
|
||||
snippetGenerators.map((gen, key) => {
|
||||
return (<div style={getBtnStyle(key)} className="btn" key={key} onClick={() => onGenChange(key)}>
|
||||
<h4 style={key === activeLanguage ? {color: "white",} : {}}>{gen.get("title")}</h4>
|
||||
</div>)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="copy-to-clipboard">
|
||||
<CopyToClipboard text={snippet}>
|
||||
<button />
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
<div>
|
||||
{SnippetComponent}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
45
src/core/plugins/request-snippets/selectors.js
Normal file
45
src/core/plugins/request-snippets/selectors.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createSelector } from "reselect"
|
||||
import { Map } from "immutable"
|
||||
|
||||
const state = state => state || Map()
|
||||
|
||||
export const getGenerators = createSelector(
|
||||
state,
|
||||
state => {
|
||||
const languageKeys = state
|
||||
.get("languages")
|
||||
const generators = state
|
||||
.get("generators", Map())
|
||||
if(!languageKeys) {
|
||||
return generators
|
||||
}
|
||||
return generators
|
||||
.filter((v, key) => languageKeys.includes(key))
|
||||
}
|
||||
)
|
||||
|
||||
export const getSnippetGenerators = (state) => ({ fn }) => {
|
||||
const getGenFn = (key) => fn[`requestSnippetGenerator_${key}`]
|
||||
return getGenerators(state)
|
||||
.map((gen, key) => {
|
||||
const genFn = getGenFn(key)
|
||||
if(typeof genFn !== "function") {
|
||||
return null
|
||||
}
|
||||
|
||||
return gen.set("fn", genFn)
|
||||
})
|
||||
.filter(v => v)
|
||||
}
|
||||
|
||||
export const getActiveLanguage = createSelector(
|
||||
state,
|
||||
state => state
|
||||
.get("activeLanguage")
|
||||
)
|
||||
|
||||
export const getDefaultExpanded = createSelector(
|
||||
state,
|
||||
state => state
|
||||
.get("defaultExpanded")
|
||||
)
|
||||
@@ -5,7 +5,7 @@ import serializeError from "serialize-error"
|
||||
import isString from "lodash/isString"
|
||||
import debounce from "lodash/debounce"
|
||||
import set from "lodash/set"
|
||||
import { isJSONObject, paramToValue, isEmptyValue } from "core/utils"
|
||||
import { paramToValue, isEmptyValue } from "core/utils"
|
||||
|
||||
// Actions conform to FSA (flux-standard-actions)
|
||||
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
||||
@@ -426,9 +426,7 @@ export const executeRequest = (req) =>
|
||||
const requestBody = oas3Selectors.requestBodyValue(pathName, method)
|
||||
const requestBodyInclusionSetting = oas3Selectors.requestBodyInclusionSetting(pathName, method)
|
||||
|
||||
if(isJSONObject(requestBody)) {
|
||||
req.requestBody = JSON.parse(requestBody)
|
||||
} else if(requestBody && requestBody.toJS) {
|
||||
if(requestBody && requestBody.toJS) {
|
||||
req.requestBody = requestBody
|
||||
.map(
|
||||
(val) => {
|
||||
@@ -445,7 +443,7 @@ export const executeRequest = (req) =>
|
||||
) || requestBodyInclusionSetting.get(key)
|
||||
)
|
||||
.toJS()
|
||||
} else{
|
||||
} else {
|
||||
req.requestBody = requestBody
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import layout from "core/plugins/layout"
|
||||
import spec from "core/plugins/spec"
|
||||
import view from "core/plugins/view"
|
||||
import samples from "core/plugins/samples"
|
||||
import requestSnippets from "core/plugins/request-snippets"
|
||||
import logs from "core/plugins/logs"
|
||||
import swaggerJs from "core/plugins/swagger-js"
|
||||
import auth from "core/plugins/auth"
|
||||
@@ -191,6 +192,7 @@ export default function() {
|
||||
downloadUrlPlugin,
|
||||
deepLinkingPlugin,
|
||||
filter,
|
||||
onComplete
|
||||
onComplete,
|
||||
requestSnippets
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import xml from "react-syntax-highlighter/dist/esm/languages/hljs/xml"
|
||||
import bash from "react-syntax-highlighter/dist/esm/languages/hljs/bash"
|
||||
import yaml from "react-syntax-highlighter/dist/esm/languages/hljs/yaml"
|
||||
import http from "react-syntax-highlighter/dist/esm/languages/hljs/http"
|
||||
import powershell from "react-syntax-highlighter/dist/esm/languages/hljs/powershell"
|
||||
import javascript from "react-syntax-highlighter/dist/esm/languages/hljs/javascript"
|
||||
|
||||
import agate from "react-syntax-highlighter/dist/esm/styles/hljs/agate"
|
||||
import arta from "react-syntax-highlighter/dist/esm/styles/hljs/arta"
|
||||
@@ -20,6 +22,8 @@ SyntaxHighlighter.registerLanguage("xml", xml)
|
||||
SyntaxHighlighter.registerLanguage("yaml", yaml)
|
||||
SyntaxHighlighter.registerLanguage("http", http)
|
||||
SyntaxHighlighter.registerLanguage("bash", bash)
|
||||
SyntaxHighlighter.registerLanguage("powershell", powershell)
|
||||
SyntaxHighlighter.registerLanguage("javascript", javascript)
|
||||
|
||||
const styles = {agate, arta, monokai, nord, obsidian, "tomorrow-night": tomorrowNight}
|
||||
export const availableStyles = Object.keys(styles)
|
||||
|
||||
@@ -32,25 +32,6 @@ const DEFAULT_RESPONSE_KEY = "default"
|
||||
|
||||
export const isImmutable = (maybe) => Im.Iterable.isIterable(maybe)
|
||||
|
||||
export function isJSONObject (str) {
|
||||
try {
|
||||
var o = JSON.parse(str)
|
||||
|
||||
// Handle non-exception-throwing cases:
|
||||
// Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
|
||||
// but... JSON.parse(null) returns null, and typeof null === "object",
|
||||
// so we must check for that, too. Thankfully, null is falsey, so this suffices:
|
||||
if (o && typeof o === "object") {
|
||||
return o
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function objectify (thing) {
|
||||
if(!isObject(thing))
|
||||
return {}
|
||||
|
||||
Reference in New Issue
Block a user