+
+ const title =
+ {name}
+
return
-
+ 1}
+ >{content}
}).toArray()
}
diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx
index 14f2122758a..358291823fc 100644
--- a/src/core/components/operation.jsx
+++ b/src/core/components/operation.jsx
@@ -9,6 +9,7 @@ export default class Operation extends PureComponent {
static propTypes = {
specPath: ImPropTypes.list.isRequired,
operation: PropTypes.instanceOf(Iterable).isRequired,
+ summary: PropTypes.string,
response: PropTypes.instanceOf(Iterable),
request: PropTypes.instanceOf(Iterable),
@@ -34,7 +35,8 @@ export default class Operation extends PureComponent {
operation: null,
response: null,
request: null,
- specPath: List()
+ specPath: List(),
+ summary: ""
}
render() {
@@ -59,6 +61,8 @@ export default class Operation extends PureComponent {
let operationProps = this.props.operation
let {
+ summary,
+ deprecated,
isShown,
isAuthorized,
path,
@@ -76,14 +80,13 @@ export default class Operation extends PureComponent {
} = operationProps.toJS()
let {
- summary,
+ summary: resolvedSummary,
description,
- deprecated,
externalDocs,
schemes
- } = op.operation
+ } = op
- let operation = operationProps.getIn(["op", "operation"])
+ let operation = operationProps.getIn(["op"])
let security = operationProps.get("security")
let responses = operation.get("responses")
let produces = operation.get("produces")
@@ -132,7 +135,7 @@ export default class Operation extends PureComponent {
{ !showSummary ? null :
- { summary }
+ { resolvedSummary || summary }
}
diff --git a/src/core/components/param-body.jsx b/src/core/components/param-body.jsx
index 13a4377f8c7..a6097c76ec2 100644
--- a/src/core/components/param-body.jsx
+++ b/src/core/components/param-body.jsx
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
- let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : fromJS({})
+ let parameter = specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : fromJS({})
let isXml = /xml/i.test(consumesValue)
let isJson = /json/i.test(consumesValue)
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
@@ -107,7 +107,7 @@ export default class ParamBody extends PureComponent {
const HighlightCode = getComponent("highlightCode")
const ContentType = getComponent("contentType")
// for domains where specSelectors not passed
- let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : param
+ let parameter = specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : param
let errors = parameter.get("errors", List())
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx
index 42f45bd9b48..b3844574965 100644
--- a/src/core/components/parameter-row.jsx
+++ b/src/core/components/parameter-row.jsx
@@ -24,7 +24,7 @@ export default class ParameterRow extends Component {
let { specSelectors, pathMethod, param } = props
let defaultValue = param.get("default")
- let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
+ let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : ""
if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
@@ -37,7 +37,7 @@ export default class ParameterRow extends Component {
let example = param.get("example")
let defaultValue = param.get("default")
- let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
+ let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
let enumValue
if(isOAS3()) {
@@ -104,8 +104,7 @@ export default class ParameterRow extends Component {
let isFormDataSupported = "FormData" in win
let required = param.get("required")
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
- let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
- let value = parameter ? parameter.get("value") : ""
+ let value = param ? param.get("value") : ""
let extensions = getExtensions(param)
diff --git a/src/core/components/parameters.jsx b/src/core/components/parameters.jsx
index c1c6ded3082..c5b1e2293ad 100644
--- a/src/core/components/parameters.jsx
+++ b/src/core/components/parameters.jsx
@@ -101,7 +101,7 @@ export default class Parameters extends Component {
specPath={specPath.push(i.toString())}
getComponent={ getComponent }
getConfigs={ getConfigs }
- param={ parameter }
+ param={ specSelectors.parameterWithMeta(pathMethod, parameter.get("name"), parameter.get("in")) }
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper}
diff --git a/src/core/components/providers/markdown.jsx b/src/core/components/providers/markdown.jsx
index ec096d5f8b1..a4cbf3f900e 100644
--- a/src/core/components/providers/markdown.jsx
+++ b/src/core/components/providers/markdown.jsx
@@ -3,7 +3,17 @@ import PropTypes from "prop-types"
import Remarkable from "remarkable"
import sanitize from "sanitize-html"
+// eslint-disable-next-line no-useless-escape
+const isPlainText = (str) => /^[A-Z\s0-9!?\.]+$/gi.test(str)
+
function Markdown({ source }) {
+ if(isPlainText(source)) {
+ // If the source text is not Markdown,
+ // let's save some time and just render it.
+ return
+ {source}
+
+ }
const html = new Remarkable({
html: true,
typographer: true,
diff --git a/src/core/containers/OperationContainer.jsx b/src/core/containers/OperationContainer.jsx
index ea698c9b7f7..ac382553a4f 100644
--- a/src/core/containers/OperationContainer.jsx
+++ b/src/core/containers/OperationContainer.jsx
@@ -2,7 +2,7 @@ import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { helpers } from "swagger-client"
-import { Iterable, fromJS } from "immutable"
+import { Iterable, fromJS, Map } from "immutable"
const { opId } = helpers
@@ -82,13 +82,24 @@ export default class OperationContainer extends PureComponent {
}
componentWillReceiveProps(nextProps) {
- if(nextProps.response !== this.props.response) {
+ const { path, method, specActions, specSelectors, response, isShown } = nextProps
+ const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method])
+
+ if(response !== this.props.response) {
this.setState({ executeInProgress: false })
}
+
+ if(isShown && resolvedSubtree === undefined) {
+ specActions.requestResolvedSubtree(["paths", path, method])
+ }
}
toggleShown =() => {
- let { layoutActions, tag, operationId, isShown } = this.props
+ let { layoutActions, specActions, tag, operationId, path, method, isShown } = this.props
+ if(!isShown) {
+ // transitioning from collapsed to expanded
+ specActions.requestResolvedSubtree(["paths", path, method])
+ }
layoutActions.show(["operations", tag, operationId], !isShown)
}
@@ -108,7 +119,7 @@ export default class OperationContainer extends PureComponent {
render() {
let {
- op,
+ op: unresolvedOp,
tag,
path,
method,
@@ -140,10 +151,14 @@ export default class OperationContainer extends PureComponent {
const Operation = getComponent( "operation" )
+ const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method]) || Map()
+
const operationProps = fromJS({
- op,
+ op: resolvedSubtree || Map(),
tag,
path,
+ summary: unresolvedOp.getIn(["operation", "summary"]) || "",
+ deprecated: resolvedSubtree.get("deprecated") || unresolvedOp.getIn(["operation", "deprecated"]) || false,
method,
security,
isAuthorized,
diff --git a/src/core/json-schema-components.js b/src/core/json-schema-components.js
index 087b617ca33..14998febd3d 100644
--- a/src/core/json-schema-components.js
+++ b/src/core/json-schema-components.js
@@ -2,6 +2,7 @@ import React, { PureComponent, Component } from "react"
import PropTypes from "prop-types"
import { List, fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
+import DebounceInput from "react-debounce-input"
//import "less/json-schema-form"
const noop = ()=> {}
@@ -79,10 +80,13 @@ export class JsonSchema_string extends Component {
disabled={isDisabled}/>)
}
else {
- return ()
diff --git a/src/core/plugins/deep-linking/spec-wrap-actions.js b/src/core/plugins/deep-linking/spec-wrap-actions.js
index d69fc46500f..398fbcbc282 100644
--- a/src/core/plugins/deep-linking/spec-wrap-actions.js
+++ b/src/core/plugins/deep-linking/spec-wrap-actions.js
@@ -4,7 +4,7 @@ import { escapeDeepLinkPath } from "core/utils"
let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed
-export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => {
+export const updateJsonSpec = (ori, { layoutActions, getConfigs }) => (...args) => {
ori(...args)
const isDeepLinkingEnabled = getConfigs().deepLinking
diff --git a/src/core/plugins/err/actions.js b/src/core/plugins/err/actions.js
index 461971cddc2..6b6f474ae30 100644
--- a/src/core/plugins/err/actions.js
+++ b/src/core/plugins/err/actions.js
@@ -6,6 +6,7 @@ export const NEW_SPEC_ERR = "err_new_spec_err"
export const NEW_SPEC_ERR_BATCH = "err_new_spec_err_batch"
export const NEW_AUTH_ERR = "err_new_auth_err"
export const CLEAR = "err_clear"
+export const CLEAR_BY = "err_clear_by"
export function newThrownErr(err) {
return {
@@ -49,3 +50,11 @@ export function clear(filter = {}) {
payload: filter
}
}
+
+export function clearBy(filter = () => true) {
+ // filter is a function
+ return {
+ type: CLEAR_BY,
+ payload: filter
+ }
+}
diff --git a/src/core/plugins/err/reducers.js b/src/core/plugins/err/reducers.js
index 795f5dd59f7..8a9cbbbae22 100644
--- a/src/core/plugins/err/reducers.js
+++ b/src/core/plugins/err/reducers.js
@@ -4,12 +4,11 @@ import {
NEW_SPEC_ERR,
NEW_SPEC_ERR_BATCH,
NEW_AUTH_ERR,
- CLEAR
+ CLEAR,
+ CLEAR_BY,
} from "./actions"
-import reject from "lodash/reject"
-
-import Im, { fromJS, List } from "immutable"
+import { fromJS, List } from "immutable"
import transformErrors from "./error-transformers/hook"
@@ -65,11 +64,34 @@ export default function(system) {
},
[CLEAR]: (state, { payload }) => {
- if(!payload) {
- return
+ if(!payload || !state.get("errors")) {
+ return state
+ }
+
+ let newErrors = state.get("errors")
+ .filter(err => {
+ return err.keySeq().every(k => {
+ const errValue = err.get(k)
+ const filterValue = payload[k]
+
+ if(!filterValue) return true
+
+ return errValue !== filterValue
+ })
+ })
+ return state.merge({
+ errors: newErrors
+ })
+ },
+
+ [CLEAR_BY]: (state, { payload }) => {
+ if(!payload || typeof payload !== "function") {
+ return state
}
- // TODO: Rework, to use immutable only, no need for lodash
- let newErrors = Im.fromJS(reject((state.get("errors") || List()).toJS(), payload))
+ let newErrors = state.get("errors")
+ .filter(err => {
+ return payload(err)
+ })
return state.merge({
errors: newErrors
})
diff --git a/src/core/plugins/oas3/spec-extensions/wrap-selectors.js b/src/core/plugins/oas3/spec-extensions/wrap-selectors.js
index 82c10f2196a..8109e2eff7f 100644
--- a/src/core/plugins/oas3/spec-extensions/wrap-selectors.js
+++ b/src/core/plugins/oas3/spec-extensions/wrap-selectors.js
@@ -20,7 +20,7 @@ const state = state => {
return state || Map()
}
-const nullSelector = createSelector(() => null)
+const nullSelector = createSelector(() => null)
const OAS3NullSelector = onlyOAS3(nullSelector)
diff --git a/src/core/plugins/spec/actions.js b/src/core/plugins/spec/actions.js
index 0d0d853a0e3..b5c719385a5 100644
--- a/src/core/plugins/spec/actions.js
+++ b/src/core/plugins/spec/actions.js
@@ -1,6 +1,7 @@
import YAML from "js-yaml"
import parseUrl from "url-parse"
import serializeError from "serialize-error"
+import { Map } from "immutable"
import isString from "lodash/isString"
import { isJSONObject } from "core/utils"
@@ -21,6 +22,7 @@ export const CLEAR_REQUEST = "spec_clear_request"
export const CLEAR_VALIDATE_PARAMS = "spec_clear_validate_param"
export const UPDATE_OPERATION_META_VALUE = "spec_update_operation_meta_value"
export const UPDATE_RESOLVED = "spec_update_resolved"
+export const UPDATE_RESOLVED_SUBTREE = "spec_update_resolved_subtree"
export const SET_SCHEME = "set_scheme"
const toStr = (str) => isString(str) ? str : ""
@@ -74,7 +76,14 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
return {}
}
+let hasWarnedAboutResolveSpecDeprecation = false
+
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => {
+ if(!hasWarnedAboutResolveSpecDeprecation) {
+ console.warn(`specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use resolveIn instead!`)
+ hasWarnedAboutResolveSpecDeprecation = true
+ }
+
const {
modelPropertyMacro,
parameterMacro,
@@ -124,6 +133,55 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
})
}
+export const requestResolvedSubtree = path => system => {
+ const {
+ errActions,
+ fn: {
+ resolveSubtree,
+ AST: { getLineNumberForPath }
+ },
+ specSelectors,
+ specActions,
+ } = system
+
+ const specStr = specSelectors.specStr()
+
+ if(!resolveSubtree) {
+ console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing.")
+ return
+ }
+
+ const currentValue = specSelectors.specResolvedSubtree(path)
+
+ if(currentValue) {
+ return
+ }
+
+ return resolveSubtree(specSelectors.specJson().toJS(), path)
+ .then(({ spec, errors }) => {
+ errActions.clear({
+ type: "thrown"
+ })
+ if(Array.isArray(errors) && errors.length > 0) {
+ let preparedErrors = errors
+ .map(err => {
+ console.error(err)
+ err.line = err.fullPath ? getLineNumberForPath(specStr, err.fullPath) : null
+ err.path = err.fullPath ? err.fullPath.join(".") : null
+ err.level = "error"
+ err.type = "thrown"
+ err.source = "resolver"
+ Object.defineProperty(err, "message", { enumerable: true, value: err.message })
+ return err
+ })
+ errActions.newThrownErrBatch(preparedErrors)
+ }
+
+ return specActions.updateResolvedSubtree(path, spec)
+ })
+ .catch(e => console.error(e))
+}
+
export function changeParam( path, paramName, paramIn, value, isXml ){
return {
type: UPDATE_PARAM,
@@ -131,6 +189,23 @@ export function changeParam( path, paramName, paramIn, value, isXml ){
}
}
+export const updateResolvedSubtree = (path, value) => {
+ return {
+ type: UPDATE_RESOLVED_SUBTREE,
+ payload: { path, value }
+ }
+}
+
+export const invalidateResolvedSubtreeCache = () => {
+ return {
+ type: UPDATE_RESOLVED_SUBTREE,
+ payload: {
+ path: [],
+ value: Map()
+ }
+ }
+}
+
export const validateParams = ( payload, isOAS3 ) =>{
return {
type: VALIDATE_PARAMS,
@@ -251,6 +326,7 @@ export const executeRequest = (req) =>
// track duration of request
const startTime = Date.now()
+
return fn.execute(req)
.then( res => {
res.duration = Date.now() - startTime
@@ -267,13 +343,22 @@ export const executeRequest = (req) =>
// I'm using extras as a way to inject properties into the final, `execute` method - It's not great. Anyone have a better idea? @ponelat
export const execute = ( { path, method, ...extras }={} ) => (system) => {
let { fn:{fetch}, specSelectors, specActions } = system
- let spec = specSelectors.spec().toJS()
+ let spec = specSelectors.specJsonWithResolvedSubtrees().toJS()
let scheme = specSelectors.operationScheme(path, method)
let { requestContentType, responseContentType } = specSelectors.contentTypeValues([path, method]).toJS()
let isXml = /xml/i.test(requestContentType)
let parameters = specSelectors.parameterValues([path, method], isXml).toJS()
- return specActions.executeRequest({fetch, spec, pathName: path, method, parameters, requestContentType, scheme, responseContentType, ...extras })
+ return specActions.executeRequest({
+ ...extras,
+ fetch,
+ spec,
+ pathName: path,
+ method, parameters,
+ requestContentType,
+ scheme,
+ responseContentType
+ })
}
export function clearResponse (path, method) {
diff --git a/src/core/plugins/spec/reducers.js b/src/core/plugins/spec/reducers.js
index f49519e0a68..c4b9d96fd95 100644
--- a/src/core/plugins/spec/reducers.js
+++ b/src/core/plugins/spec/reducers.js
@@ -1,7 +1,12 @@
-import { fromJS } from "immutable"
+import { fromJS, List } from "immutable"
import { fromJSOrdered, validateParam } from "core/utils"
import win from "../../window"
+// selector-in-reducer is suboptimal, but `operationWithMeta` is more of a helper
+import {
+ operationWithMeta
+} from "./selectors"
+
import {
UPDATE_SPEC,
UPDATE_URL,
@@ -12,6 +17,7 @@ import {
SET_REQUEST,
SET_MUTATED_REQUEST,
UPDATE_RESOLVED,
+ UPDATE_RESOLVED_SUBTREE,
UPDATE_OPERATION_META_VALUE,
CLEAR_RESPONSE,
CLEAR_REQUEST,
@@ -39,38 +45,38 @@ export default {
return state.setIn(["resolved"], fromJSOrdered(action.payload))
},
+ [UPDATE_RESOLVED_SUBTREE]: (state, action) => {
+ const { value, path } = action.payload
+ return state.setIn(["resolvedSubtrees", ...path], fromJSOrdered(value))
+ },
+
[UPDATE_PARAM]: ( state, {payload} ) => {
- let { path, paramName, paramIn, value, isXml } = payload
-
- return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
- const index = parameters.findIndex(p => p.get( "name" ) === paramName && p.get("in") === paramIn )
- if (!(value instanceof win.File)) {
- value = fromJSOrdered( value )
- }
- return parameters.setIn( [ index, isXml ? "value_xml" : "value" ], value)
- })
+ let { path: pathMethod, paramName, paramIn, value, isXml } = payload
+
+ const valueKey = isXml ? "value_xml" : "value"
+
+ return state.setIn(
+ ["meta", "paths", ...pathMethod, "parameters", `${paramName}.${paramIn}`, valueKey],
+ value
+ )
},
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
let meta = state.getIn( [ "meta", "paths", ...pathMethod ], fromJS({}) )
let isXml = /xml/i.test(meta.get("consumes_value"))
- return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
- return parameters.withMutations( parameters => {
- for ( let i = 0, len = parameters.count(); i < len; i++ ) {
- let errors = validateParam(parameters.get(i), isXml, isOAS3)
- parameters.setIn([i, "errors"], fromJS(errors))
- }
- })
+ const op = operationWithMeta(state, ...pathMethod)
+
+ return state.updateIn(["meta", "paths", ...pathMethod, "parameters"], fromJS({}), paramMeta => {
+ return op.get("parameters", List()).reduce((res, param) => {
+ const errors = validateParam(param, isXml, isOAS3)
+ return res.setIn([`${param.get("name")}.${param.get("in")}`, "errors"], fromJS(errors))
+ }, paramMeta)
})
},
[CLEAR_VALIDATE_PARAMS]: ( state, { payload: { pathMethod } } ) => {
- return state.updateIn( [ "resolved", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
- return parameters.withMutations( parameters => {
- for ( let i = 0, len = parameters.count(); i < len; i++ ) {
- parameters.setIn([i, "errors"], fromJS([]))
- }
- })
+ return state.updateIn( [ "meta", "paths", ...pathMethod, "parameters" ], fromJS([]), parameters => {
+ return parameters.map(param => param.set("errors", fromJS([])))
})
},
@@ -109,10 +115,10 @@ export default {
[UPDATE_OPERATION_META_VALUE]: (state, { payload: { path, value, key } }) => {
// path is a pathMethod tuple... can't change the name now.
- let operationPath = ["resolved", "paths", ...path]
+ let operationPath = ["paths", ...path]
let metaPath = ["meta", "paths", ...path]
- if(!state.getIn(operationPath)) {
+ if(!state.getIn(["json", ...operationPath]) && !state.getIn(["resolved", ...operationPath])) {
// do nothing if the operation does not exist
return state
}
diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js
index e19c590c31b..f8fa9a38df6 100644
--- a/src/core/plugins/spec/selectors.js
+++ b/src/core/plugins/spec/selectors.js
@@ -42,9 +42,18 @@ export const specResolved = createSelector(
spec => spec.get("resolved", Map())
)
+export const specResolvedSubtree = (state, path) => {
+ return state.getIn(["resolvedSubtrees", ...path], undefined)
+}
+
+export const specJsonWithResolvedSubtrees = createSelector(
+ state,
+ spec => Map().merge(spec.get("json"), spec.get("resolvedSubtrees"))
+)
+
// Default Spec ( as an object )
export const spec = state => {
- let res = specResolved(state)
+ let res = specJson(state)
return res
}
@@ -137,7 +146,9 @@ export const securityDefinitions = createSelector(
export const findDefinition = ( state, name ) => {
- return specResolved(state).getIn(["definitions", name], null)
+ const resolvedRes = state.getIn(["resolvedSubtrees", "definitions", name], null)
+ const unresolvedRes = state.getIn(["json", "definitions", name], null)
+ return resolvedRes || unresolvedRes || null
}
export const definitions = createSelector(
@@ -261,10 +272,40 @@ export const allowTryItOutFor = () => {
return true
}
+export const operationWithMeta = (state, path, method) => {
+ const op = specJsonWithResolvedSubtrees(state).getIn(["paths", path, method], Map())
+ const meta = state.getIn(["meta", "paths", path, method], Map())
+
+ const mergedParams = op.get("parameters", List()).map((param) => {
+ return Map().merge(
+ param,
+ meta.getIn(["parameters", `${param.get("name")}.${param.get("in")}`])
+ )
+ })
+
+ return Map()
+ .merge(op, meta)
+ .set("parameters", mergedParams)
+}
+
+export const parameterWithMeta = (state, pathMethod, paramName, paramIn) => {
+ const opParams = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "parameters"], Map())
+ const metaParams = state.getIn(["meta", "paths", ...pathMethod, "parameters"], Map())
+
+ const mergedParams = opParams.map((param) => {
+ return Map().merge(
+ param,
+ metaParams.get(`${param.get("name")}.${param.get("in")}`)
+ )
+ })
+
+ return mergedParams.find(param => param.get("in") === paramIn && param.get("name") === paramName, Map())
+}
+
// Get the parameter value by parameter name
export function getParameter(state, pathMethod, name, inType) {
pathMethod = pathMethod || []
- let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
+ let params = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
return params.find( (p) => {
return Map.isMap(p) && p.get("name") === name && p.get("in") === inType
}) || Map() // Always return a map
@@ -281,8 +322,9 @@ export const hasHost = createSelector(
// Get the parameter values, that the user filled out
export function parameterValues(state, pathMethod, isXml) {
pathMethod = pathMethod || []
- let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
- return params.reduce( (hash, p) => {
+ // let paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
+ let paramValues = operationWithMeta(state, ...pathMethod).get("parameters", List())
+ return paramValues.reduce( (hash, p) => {
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
return hash.set(`${p.get("in")}.${p.get("name")}`, value)
}, fromJS({}))
@@ -305,7 +347,7 @@ export function parametersIncludeType(parameters, typeValue="") {
// Get the consumes/produces value that the user selected
export function contentTypeValues(state, pathMethod) {
pathMethod = pathMethod || []
- let op = spec(state).getIn(["paths", ...pathMethod], fromJS({}))
+ let op = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod], fromJS({}))
let meta = state.getIn(["meta", "paths", ...pathMethod], fromJS({}))
let producesValue = currentProducesFor(state, pathMethod)
@@ -327,14 +369,14 @@ export function contentTypeValues(state, pathMethod) {
// Get the consumes/produces by path
export function operationConsumes(state, pathMethod) {
pathMethod = pathMethod || []
- return spec(state).getIn(["paths", ...pathMethod, "consumes"], fromJS({}))
+ return state.getIn(["meta", ...pathMethod, "consumes"], fromJS({}))
}
// Get the currently selected produces value for an operation
export function currentProducesFor(state, pathMethod) {
pathMethod = pathMethod || []
- const operation = spec(state).getIn(["paths", ...pathMethod], null)
+ const operation = specJsonWithResolvedSubtrees(state).getIn([ "paths", ...pathMethod], null)
if(operation === null) {
// return nothing if the operation does not exist
@@ -362,10 +404,10 @@ export const canExecuteScheme = ( state, path, method ) => {
export const validateBeforeExecute = ( state, pathMethod ) => {
pathMethod = pathMethod || []
- let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
+ let paramValues = state.getIn(["meta", "paths", ...pathMethod, "parameters"], fromJS([]))
let isValid = true
- params.forEach( (p) => {
+ paramValues.forEach( (p) => {
let errors = p.get("errors")
if ( errors && errors.count() ) {
isValid = false
diff --git a/src/core/plugins/spec/wrap-actions.js b/src/core/plugins/spec/wrap-actions.js
index a9c73f22baa..324ddda1d9c 100644
--- a/src/core/plugins/spec/wrap-actions.js
+++ b/src/core/plugins/spec/wrap-actions.js
@@ -5,7 +5,7 @@ export const updateSpec = (ori, {specActions}) => (...args) => {
export const updateJsonSpec = (ori, {specActions}) => (...args) => {
ori(...args)
- specActions.resolveSpec(...args)
+ specActions.invalidateResolvedSubtreeCache()
}
// Log the request ( just for debugging, shouldn't affect prod )
@@ -16,4 +16,4 @@ export const executeRequest = (ori, { specActions }) => (req) => {
export const validateParams = (ori, { specSelectors }) => (req) => {
return ori(req, specSelectors.isOAS3())
-}
\ No newline at end of file
+}
diff --git a/src/core/plugins/swagger-js/index.js b/src/core/plugins/swagger-js/index.js
index d8744c19922..90ceeca3619 100644
--- a/src/core/plugins/swagger-js/index.js
+++ b/src/core/plugins/swagger-js/index.js
@@ -7,6 +7,7 @@ module.exports = function({ configs }) {
buildRequest: Swagger.buildRequest,
execute: Swagger.execute,
resolve: Swagger.resolve,
+ resolveSubtree: Swagger.resolveSubtree,
serializeRes: Swagger.serializeRes,
opId: Swagger.helpers.opId
}
diff --git a/src/style/_models.scss b/src/style/_models.scss
index 5b69b3fd159..2ee50c281ed 100644
--- a/src/style/_models.scss
+++ b/src/style/_models.scss
@@ -198,6 +198,7 @@ section.models
.model-box
{
padding: 10px;
+ display: inline-block;
border-radius: 4px;
background: rgba($section-models-model-box-background-color,.1);
diff --git a/test/components/models.js b/test/components/models.js
index 0280e0fba49..11a8b7f4434 100644
--- a/test/components/models.js
+++ b/test/components/models.js
@@ -24,7 +24,8 @@ describe("", function(){
def1: {},
def2: {}
})
- }
+ },
+ specResolvedSubtree: () => {}
},
layoutSelectors: {
isShown: createSpy()
diff --git a/test/core/plugins/spec/actions.js b/test/core/plugins/spec/actions.js
index 4a5846da924..58aec54eef1 100644
--- a/test/core/plugins/spec/actions.js
+++ b/test/core/plugins/spec/actions.js
@@ -177,6 +177,10 @@ describe("spec plugin - actions", function(){
})
})
+ describe("requestResolvedSubtree", () => {
+ it("should return a promise ")
+ })
+
it.skip("should call errActions.newErr, if the fn.execute rejects", function(){
})
diff --git a/test/core/plugins/spec/selectors.js b/test/core/plugins/spec/selectors.js
index 824464899f9..a11699ef110 100644
--- a/test/core/plugins/spec/selectors.js
+++ b/test/core/plugins/spec/selectors.js
@@ -24,7 +24,7 @@ describe("spec plugin - selectors", function(){
// Given
const spec = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {
@@ -55,7 +55,7 @@ describe("spec plugin - selectors", function(){
it("should return { requestContentType, responseContentType } from an operation", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {}
@@ -86,7 +86,7 @@ describe("spec plugin - selectors", function(){
it("should default to the first `produces` array value if current is not set", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {
@@ -121,7 +121,7 @@ describe("spec plugin - selectors", function(){
it("should default to `application/json` if a default produces value is not available", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {}
@@ -151,7 +151,7 @@ describe("spec plugin - selectors", function(){
it("should prioritize consumes value first from an operation", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {
@@ -182,7 +182,7 @@ describe("spec plugin - selectors", function(){
it("should fallback to multipart/form-data if there is no consumes value but there is a file parameter", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {
@@ -204,7 +204,7 @@ describe("spec plugin - selectors", function(){
it("should fallback to application/x-www-form-urlencoded if there is no consumes value, no file parameter, but there is a formData parameter", function(){
// Given
let state = fromJS({
- resolved: {
+ json: {
paths: {
"/one": {
get: {
@@ -244,7 +244,7 @@ describe("spec plugin - selectors", function(){
// Given
let state = fromJS({
url: "https://generator.swagger.io/api/swagger.json",
- resolved: {
+ json: {
paths: {
"/one": {
get: {