Skip to content

Commit 8777d8b

Browse files
authored
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
1 parent 22036b1 commit 8777d8b

File tree

6 files changed

+128
-11
lines changed

6 files changed

+128
-11
lines changed

src/core/components/operation.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ export default class Operation extends PureComponent {
156156

157157
<Collapse isOpened={isShown}>
158158
<div className="opblock-body">
159-
{ operation && operation.size ? null :
159+
{ (operation && operation.size) || operation === null ? null :
160160
<img height={"32px"} width={"32px"} src={require("core/../img/rolling-load.svg")} className="opblock-loading-animation" />
161161
}
162162
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}

src/core/containers/OperationContainer.jsx

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,23 @@ export default class OperationContainer extends PureComponent {
8282
}
8383

8484
componentWillReceiveProps(nextProps) {
85-
const { path, method, specActions, specSelectors, response, isShown } = nextProps
86-
const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method])
85+
const { response, isShown } = nextProps
86+
const resolvedSubtree = this.getResolvedSubtree()
8787

8888
if(response !== this.props.response) {
8989
this.setState({ executeInProgress: false })
9090
}
9191

9292
if(isShown && resolvedSubtree === undefined) {
93-
specActions.requestResolvedSubtree(["paths", path, method])
93+
this.requestResolvedSubtree()
9494
}
9595
}
9696

9797
toggleShown =() => {
98-
let { layoutActions, specActions, tag, operationId, path, method, isShown } = this.props
98+
let { layoutActions, tag, operationId, isShown } = this.props
9999
if(!isShown) {
100100
// transitioning from collapsed to expanded
101-
specActions.requestResolvedSubtree(["paths", path, method])
101+
this.requestResolvedSubtree()
102102
}
103103
layoutActions.show(["operations", tag, operationId], !isShown)
104104
}
@@ -117,6 +117,37 @@ export default class OperationContainer extends PureComponent {
117117
this.setState({ executeInProgress: true })
118118
}
119119

120+
getResolvedSubtree = () => {
121+
const {
122+
specSelectors,
123+
path,
124+
method,
125+
specPath
126+
} = this.props
127+
128+
if(specPath) {
129+
return specSelectors.specResolvedSubtree(specPath.toJS()) || Map()
130+
}
131+
132+
return specSelectors.specResolvedSubtree(["paths", path, method]) || Map()
133+
}
134+
135+
requestResolvedSubtree = () => {
136+
const {
137+
specActions,
138+
path,
139+
method,
140+
specPath
141+
} = this.props
142+
143+
144+
if(specPath) {
145+
return specActions.requestResolvedSubtree(specPath.toJS())
146+
}
147+
148+
return specActions.requestResolvedSubtree(["paths", path, method])
149+
}
150+
120151
render() {
121152
let {
122153
op: unresolvedOp,
@@ -151,7 +182,7 @@ export default class OperationContainer extends PureComponent {
151182

152183
const Operation = getComponent( "operation" )
153184

154-
const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method]) || Map()
185+
const resolvedSubtree = this.getResolvedSubtree()
155186

156187
const operationProps = fromJS({
157188
op: resolvedSubtree || Map(),

src/core/plugins/oas3/components/callbacks.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import ImPropTypes from "react-immutable-proptypes"
44
import { fromJS } from "immutable"
55

66
const Callbacks = (props) => {
7-
let { callbacks, getComponent } = props
7+
let { callbacks, getComponent, specPath } = props
88
// const Markdown = getComponent("Markdown")
99
const OperationContainer = getComponent("OperationContainer", true)
1010

@@ -28,6 +28,7 @@ const Callbacks = (props) => {
2828
tag={""}
2929
method={method}
3030
path={pathItemName}
31+
specPath={specPath.push(callbackName, pathItemName, method)}
3132
allowTryItOut={false}
3233
/>
3334
}) }
@@ -42,8 +43,8 @@ const Callbacks = (props) => {
4243

4344
Callbacks.propTypes = {
4445
getComponent: PropTypes.func.isRequired,
45-
callbacks: ImPropTypes.iterable.isRequired
46-
46+
callbacks: ImPropTypes.iterable.isRequired,
47+
specPath: ImPropTypes.list.isRequired,
4748
}
4849

4950
export default Callbacks

src/core/plugins/oas3/wrap-components/parameters.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ class Parameters extends Component {
161161
</div> : "" }
162162

163163
{this.state.callbackVisible ? <div className="callbacks-container opblock-description-wrapper">
164-
<Callbacks callbacks={Map(operation.get("callbacks"))} />
164+
<Callbacks
165+
callbacks={Map(operation.get("callbacks"))}
166+
specPath={specPath.slice(0, -1).push("callbacks")}
167+
/>
165168
</div> : "" }
166169
{
167170
isOAS3() && requestBody && this.state.parametersVisible &&
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
describe("render pet api container", function () {
2+
let mainPage
3+
let apiWrapper
4+
beforeEach(function (client, done) {
5+
mainPage = client
6+
.url("localhost:3200")
7+
.page.main()
8+
9+
client.waitForElementVisible(".download-url-input", 5000)
10+
.pause(5000)
11+
.clearValue(".download-url-input")
12+
.setValue(".download-url-input", "http://localhost:3200/test-specs/callbacks.openapi.yaml")
13+
.click("button.download-url-button")
14+
.pause(1000)
15+
16+
apiWrapper = mainPage.section.apiWrapper
17+
18+
done()
19+
})
20+
afterEach(function (client, done) {
21+
done()
22+
})
23+
describe("POST /pet", () => {
24+
it("should render a callback correctly", function (client) {
25+
apiWrapper.waitForElementVisible("#operations-pet-addPet", 10000)
26+
// Expand the operation
27+
.click("#operations-pet-addPet")
28+
.waitForElementVisible("#operations-pet-addPet > div:nth-child(2) > div", 5000)
29+
// Switch to Callbacks tab
30+
.click("#operations-pet-addPet div.tab-header > div.tab-item.false > h4 > span")
31+
.waitForElementVisible("#operations-pet-addPet div.callbacks-container", 5000)
32+
.assert.containsText("#operations--post_request_body__url > div > span.opblock-summary-path", "$request.body#/url")
33+
.click("#operations--post_request_body__url")
34+
.waitForElementVisible("#operations--post_request_body__url div.response-col_description__inner > div > div > p", 5000)
35+
.assert.containsText("#operations--post_request_body__url div.response-col_description__inner > div > div > p", "webhook successfully processed and no retries will be performed")
36+
37+
38+
client.end()
39+
})
40+
})
41+
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: http://petstore.swagger.io/v2
4+
info:
5+
version: 1.0.0
6+
title: Swagger Petstore
7+
termsOfService: http://swagger.io/terms/
8+
contact:
9+
10+
license:
11+
name: Apache 2.0
12+
url: http://www.apache.org/licenses/LICENSE-2.0.html
13+
paths:
14+
"/pet":
15+
post:
16+
tags:
17+
- pet
18+
summary: Add a new pet to the store
19+
description: ''
20+
operationId: addPet
21+
parameters: []
22+
responses:
23+
'405':
24+
description: Invalid input
25+
security:
26+
- petstore_auth:
27+
- write:pets
28+
- read:pets
29+
callbacks:
30+
myWebhook:
31+
'$request.body#/url':
32+
post:
33+
requestBody:
34+
description: Callback payload
35+
content:
36+
'application/json':
37+
schema:
38+
type: string
39+
responses:
40+
'200':
41+
description: webhook successfully processed and no retries will be performed

0 commit comments

Comments
 (0)