fix: use specPath prop to resolve operations in OperationContainer (#4272)
* Use `parameterWithMeta` to get parameter data in <ParameterRow> * Prefer specPath when fetching resolved subtrees in OperationContainer * Add test for OAS3 callback rendering * Remove debugger statement
This commit is contained in:
@@ -156,7 +156,7 @@ export default class Operation extends PureComponent {
|
||||
|
||||
<Collapse isOpened={isShown}>
|
||||
<div className="opblock-body">
|
||||
{ operation && operation.size ? null :
|
||||
{ (operation && operation.size) || operation === null ? null :
|
||||
<img height={"32px"} width={"32px"} src={require("core/../img/rolling-load.svg")} className="opblock-loading-animation" />
|
||||
}
|
||||
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
|
||||
|
||||
@@ -82,23 +82,23 @@ export default class OperationContainer extends PureComponent {
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { path, method, specActions, specSelectors, response, isShown } = nextProps
|
||||
const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method])
|
||||
const { response, isShown } = nextProps
|
||||
const resolvedSubtree = this.getResolvedSubtree()
|
||||
|
||||
if(response !== this.props.response) {
|
||||
this.setState({ executeInProgress: false })
|
||||
}
|
||||
|
||||
if(isShown && resolvedSubtree === undefined) {
|
||||
specActions.requestResolvedSubtree(["paths", path, method])
|
||||
this.requestResolvedSubtree()
|
||||
}
|
||||
}
|
||||
|
||||
toggleShown =() => {
|
||||
let { layoutActions, specActions, tag, operationId, path, method, isShown } = this.props
|
||||
let { layoutActions, tag, operationId, isShown } = this.props
|
||||
if(!isShown) {
|
||||
// transitioning from collapsed to expanded
|
||||
specActions.requestResolvedSubtree(["paths", path, method])
|
||||
this.requestResolvedSubtree()
|
||||
}
|
||||
layoutActions.show(["operations", tag, operationId], !isShown)
|
||||
}
|
||||
@@ -117,6 +117,37 @@ export default class OperationContainer extends PureComponent {
|
||||
this.setState({ executeInProgress: true })
|
||||
}
|
||||
|
||||
getResolvedSubtree = () => {
|
||||
const {
|
||||
specSelectors,
|
||||
path,
|
||||
method,
|
||||
specPath
|
||||
} = this.props
|
||||
|
||||
if(specPath) {
|
||||
return specSelectors.specResolvedSubtree(specPath.toJS()) || Map()
|
||||
}
|
||||
|
||||
return specSelectors.specResolvedSubtree(["paths", path, method]) || Map()
|
||||
}
|
||||
|
||||
requestResolvedSubtree = () => {
|
||||
const {
|
||||
specActions,
|
||||
path,
|
||||
method,
|
||||
specPath
|
||||
} = this.props
|
||||
|
||||
|
||||
if(specPath) {
|
||||
return specActions.requestResolvedSubtree(specPath.toJS())
|
||||
}
|
||||
|
||||
return specActions.requestResolvedSubtree(["paths", path, method])
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
op: unresolvedOp,
|
||||
@@ -151,7 +182,7 @@ export default class OperationContainer extends PureComponent {
|
||||
|
||||
const Operation = getComponent( "operation" )
|
||||
|
||||
const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method]) || Map()
|
||||
const resolvedSubtree = this.getResolvedSubtree()
|
||||
|
||||
const operationProps = fromJS({
|
||||
op: resolvedSubtree || Map(),
|
||||
|
||||
@@ -4,7 +4,7 @@ import ImPropTypes from "react-immutable-proptypes"
|
||||
import { fromJS } from "immutable"
|
||||
|
||||
const Callbacks = (props) => {
|
||||
let { callbacks, getComponent } = props
|
||||
let { callbacks, getComponent, specPath } = props
|
||||
// const Markdown = getComponent("Markdown")
|
||||
const OperationContainer = getComponent("OperationContainer", true)
|
||||
|
||||
@@ -28,6 +28,7 @@ const Callbacks = (props) => {
|
||||
tag={""}
|
||||
method={method}
|
||||
path={pathItemName}
|
||||
specPath={specPath.push(callbackName, pathItemName, method)}
|
||||
allowTryItOut={false}
|
||||
/>
|
||||
}) }
|
||||
@@ -42,8 +43,8 @@ const Callbacks = (props) => {
|
||||
|
||||
Callbacks.propTypes = {
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
callbacks: ImPropTypes.iterable.isRequired
|
||||
|
||||
callbacks: ImPropTypes.iterable.isRequired,
|
||||
specPath: ImPropTypes.list.isRequired,
|
||||
}
|
||||
|
||||
export default Callbacks
|
||||
|
||||
@@ -161,7 +161,10 @@ class Parameters extends Component {
|
||||
</div> : "" }
|
||||
|
||||
{this.state.callbackVisible ? <div className="callbacks-container opblock-description-wrapper">
|
||||
<Callbacks callbacks={Map(operation.get("callbacks"))} />
|
||||
<Callbacks
|
||||
callbacks={Map(operation.get("callbacks"))}
|
||||
specPath={specPath.slice(0, -1).push("callbacks")}
|
||||
/>
|
||||
</div> : "" }
|
||||
{
|
||||
isOAS3() && requestBody && this.state.parametersVisible &&
|
||||
|
||||
41
test/e2e/scenarios/oas3/callbacks.js
Normal file
41
test/e2e/scenarios/oas3/callbacks.js
Normal file
@@ -0,0 +1,41 @@
|
||||
describe("render pet api container", function () {
|
||||
let mainPage
|
||||
let apiWrapper
|
||||
beforeEach(function (client, done) {
|
||||
mainPage = client
|
||||
.url("localhost:3200")
|
||||
.page.main()
|
||||
|
||||
client.waitForElementVisible(".download-url-input", 5000)
|
||||
.pause(5000)
|
||||
.clearValue(".download-url-input")
|
||||
.setValue(".download-url-input", "http://localhost:3200/test-specs/callbacks.openapi.yaml")
|
||||
.click("button.download-url-button")
|
||||
.pause(1000)
|
||||
|
||||
apiWrapper = mainPage.section.apiWrapper
|
||||
|
||||
done()
|
||||
})
|
||||
afterEach(function (client, done) {
|
||||
done()
|
||||
})
|
||||
describe("POST /pet", () => {
|
||||
it("should render a callback correctly", function (client) {
|
||||
apiWrapper.waitForElementVisible("#operations-pet-addPet", 10000)
|
||||
// Expand the operation
|
||||
.click("#operations-pet-addPet")
|
||||
.waitForElementVisible("#operations-pet-addPet > div:nth-child(2) > div", 5000)
|
||||
// Switch to Callbacks tab
|
||||
.click("#operations-pet-addPet div.tab-header > div.tab-item.false > h4 > span")
|
||||
.waitForElementVisible("#operations-pet-addPet div.callbacks-container", 5000)
|
||||
.assert.containsText("#operations--post_request_body__url > div > span.opblock-summary-path", "$request.body#/url")
|
||||
.click("#operations--post_request_body__url")
|
||||
.waitForElementVisible("#operations--post_request_body__url div.response-col_description__inner > div > div > p", 5000)
|
||||
.assert.containsText("#operations--post_request_body__url div.response-col_description__inner > div > div > p", "webhook successfully processed and no retries will be performed")
|
||||
|
||||
|
||||
client.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
41
test/e2e/specs/callbacks.openapi.yaml
Normal file
41
test/e2e/specs/callbacks.openapi.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
openapi: 3.0.0
|
||||
servers:
|
||||
- url: http://petstore.swagger.io/v2
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: Swagger Petstore
|
||||
termsOfService: http://swagger.io/terms/
|
||||
contact:
|
||||
email: apiteam@swagger.io
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
paths:
|
||||
"/pet":
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Add a new pet to the store
|
||||
description: ''
|
||||
operationId: addPet
|
||||
parameters: []
|
||||
responses:
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_auth:
|
||||
- write:pets
|
||||
- read:pets
|
||||
callbacks:
|
||||
myWebhook:
|
||||
'$request.body#/url':
|
||||
post:
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: webhook successfully processed and no retries will be performed
|
||||
Reference in New Issue
Block a user