Skip to content

Commit 0256b97

Browse files
authored
Merge pull request #3972 from shockey/ft/3820-oas3-path-operation-servers
OAS3: Path & Operation Servers
2 parents 5015348 + 61eb86e commit 0256b97

File tree

14 files changed

+651
-98
lines changed

14 files changed

+651
-98
lines changed

src/core/components/layouts/base.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ export default class BaseLayout extends React.Component {
9494
) : null }
9595

9696
{ servers && servers.size ? (
97-
<div className="server-container">
97+
<div className="global-server-container">
9898
<Col className="servers wrapper" mobile={12}>
99+
<span className="servers-title">Server</span>
99100
<Servers
100101
servers={servers}
101102
currentServer={oas3Selectors.selectedServer()}

src/core/components/operation.jsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default class Operation extends PureComponent {
2222
specActions: PropTypes.object.isRequired,
2323
specSelectors: PropTypes.object.isRequired,
2424
oas3Actions: PropTypes.object.isRequired,
25+
oas3Selectors: PropTypes.object.isRequired,
2526
layoutActions: PropTypes.object.isRequired,
2627
layoutSelectors: PropTypes.object.isRequired,
2728
fn: PropTypes.object.isRequired
@@ -48,7 +49,8 @@ export default class Operation extends PureComponent {
4849
specSelectors,
4950
authActions,
5051
authSelectors,
51-
oas3Actions
52+
oas3Actions,
53+
oas3Selectors
5254
} = this.props
5355
let operationProps = this.props.operation
5456

@@ -96,6 +98,7 @@ export default class Operation extends PureComponent {
9698
const Collapse = getComponent( "Collapse" )
9799
const Markdown = getComponent( "Markdown" )
98100
const Schemes = getComponent( "schemes" )
101+
const OperationServers = getComponent( "OperationServers" )
99102
const OperationExt = getComponent( "OperationExt" )
100103

101104
const { showExtensions } = getConfigs()
@@ -182,6 +185,21 @@ export default class Operation extends PureComponent {
182185
getConfigs={ getConfigs }
183186
/>
184187

188+
{ !tryItOutEnabled ? null :
189+
<OperationServers
190+
getComponent={getComponent}
191+
path={path}
192+
method={method}
193+
operationServers={operation.get("servers")}
194+
pathServers={specSelectors.paths().getIn([path, "servers"])}
195+
getSelectedServer={oas3Selectors.selectedServer}
196+
setSelectedServer={oas3Actions.setSelectedServer}
197+
setServerVariableValue={oas3Actions.setServerVariableValue}
198+
getServerVariable={oas3Selectors.serverVariableValue}
199+
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
200+
/>
201+
}
202+
185203
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
186204
<Schemes schemes={ schemes }
187205
path={ path }

src/core/containers/OperationContainer.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default class OperationContainer extends PureComponent {
3535
getComponent: PropTypes.func.isRequired,
3636
authActions: PropTypes.object,
3737
oas3Actions: PropTypes.object,
38+
oas3Selectors: PropTypes.object,
3839
authSelectors: PropTypes.object,
3940
specActions: PropTypes.object.isRequired,
4041
specSelectors: PropTypes.object.isRequired,
@@ -149,6 +150,7 @@ export default class OperationContainer extends PureComponent {
149150
authActions,
150151
authSelectors,
151152
oas3Actions,
153+
oas3Selectors,
152154
fn
153155
} = this.props
154156

@@ -189,6 +191,7 @@ export default class OperationContainer extends PureComponent {
189191
specActions={ specActions }
190192
specSelectors={ specSelectors }
191193
oas3Actions={oas3Actions}
194+
oas3Selectors={oas3Selectors}
192195
layoutActions={ layoutActions }
193196
layoutSelectors={ layoutSelectors }
194197
authActions={ authActions }

src/core/plugins/oas3/actions.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type"
77
export const UPDATE_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type"
88
export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value"
99

10-
export function setSelectedServer (selectedServerUrl) {
10+
export function setSelectedServer (selectedServerUrl, namespace) {
1111
return {
1212
type: UPDATE_SELECTED_SERVER,
13-
payload: selectedServerUrl
13+
payload: {selectedServerUrl, namespace}
1414
}
1515
}
1616

@@ -35,9 +35,9 @@ export function setResponseContentType ({ value, path, method }) {
3535
}
3636
}
3737

38-
export function setServerVariableValue ({ server, key, val }) {
38+
export function setServerVariableValue ({ server, namespace, key, val }) {
3939
return {
4040
type: UPDATE_SERVER_VARIABLE_VALUE,
41-
payload: { server, key, val }
41+
payload: { server, namespace, key, val }
4242
}
4343
}

src/core/plugins/oas3/components/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import OperationLink from "./operation-link.jsx"
44
import Servers from "./servers"
55
import RequestBodyEditor from "./request-body-editor"
66
import HttpAuth from "./http-auth"
7+
import OperationServers from "./operation-servers"
78

89
export default {
910
Callbacks,
1011
HttpAuth,
1112
RequestBody,
1213
Servers,
1314
RequestBodyEditor,
15+
OperationServers,
1416
operationLink: OperationLink
1517
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React from "react"
2+
import PropTypes from "prop-types"
3+
import ImPropTypes from "react-immutable-proptypes"
4+
5+
export default class OperationServers extends React.Component {
6+
static propTypes = {
7+
// for self
8+
path: PropTypes.string.isRequired,
9+
method: PropTypes.string.isRequired,
10+
operationServers: ImPropTypes.list,
11+
pathServers: ImPropTypes.list,
12+
setSelectedServer: PropTypes.func.isRequired,
13+
setServerVariableValue: PropTypes.func.isRequired,
14+
getSelectedServer: PropTypes.func.isRequired,
15+
getServerVariable: PropTypes.func.isRequired,
16+
getEffectiveServerValue: PropTypes.func.isRequired,
17+
18+
// utils
19+
getComponent: PropTypes.func.isRequired
20+
}
21+
22+
setSelectedServer = (server) => {
23+
const { path, method } = this.props
24+
// FIXME: we should be keeping up with this in props/state upstream of us
25+
// instead of cheating™ with `forceUpdate`
26+
this.forceUpdate()
27+
return this.props.setSelectedServer(server, `${path}:${method}`)
28+
}
29+
30+
setServerVariableValue = (obj) => {
31+
const { path, method } = this.props
32+
// FIXME: we should be keeping up with this in props/state upstream of us
33+
// instead of cheating™ with `forceUpdate`
34+
this.forceUpdate()
35+
return this.props.setServerVariableValue({
36+
...obj,
37+
namespace: `${path}:${method}`
38+
})
39+
}
40+
41+
getSelectedServer = () => {
42+
const { path, method } = this.props
43+
return this.props.getSelectedServer(`${path}:${method}`)
44+
}
45+
46+
getServerVariable = (server, key) => {
47+
const { path, method } = this.props
48+
return this.props.getServerVariable({
49+
namespace: `${path}:${method}`,
50+
server
51+
}, key)
52+
}
53+
54+
getEffectiveServerValue = (server) => {
55+
const { path, method } = this.props
56+
return this.props.getEffectiveServerValue({
57+
server,
58+
namespace: `${path}:${method}`
59+
})
60+
}
61+
62+
render() {
63+
const {
64+
// for self
65+
operationServers,
66+
pathServers,
67+
68+
// util
69+
getComponent
70+
} = this.props
71+
72+
if(!operationServers && !pathServers) {
73+
return null
74+
}
75+
76+
const Servers = getComponent("Servers")
77+
78+
const serversToDisplay = operationServers || pathServers
79+
const displaying = operationServers ? "operation" : "path"
80+
81+
return <div className="opblock-section operation-servers">
82+
<div className="opblock-section-header">
83+
<div className="tab-header">
84+
<h4 className="opblock-title">Servers</h4>
85+
</div>
86+
</div>
87+
<div className="opblock-description-wrapper">
88+
<h4 className="message">
89+
These {displaying}-level options override the global server options.
90+
</h4>
91+
<Servers
92+
servers={serversToDisplay}
93+
currentServer={this.getSelectedServer()}
94+
setSelectedServer={this.setSelectedServer}
95+
setServerVariableValue={this.setServerVariableValue}
96+
getServerVariable={this.getServerVariable}
97+
getEffectiveServerValue={this.getEffectiveServerValue}
98+
/>
99+
</div>
100+
</div>
101+
}
102+
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ export default class Servers extends React.Component {
1515
}
1616

1717
componentDidMount() {
18-
let { servers } = this.props
18+
let { servers, currentServer } = this.props
19+
20+
if(currentServer) {
21+
return
22+
}
1923

2024
//fire 'change' event to set default 'value' of select
2125
this.setServer(servers.first().get("url"))
@@ -93,9 +97,8 @@ export default class Servers extends React.Component {
9397
let shouldShowVariableUI = currentServerVariableDefs.size !== 0
9498

9599
return (
96-
<div>
100+
<div className="servers">
97101
<label htmlFor="servers">
98-
<span className="servers-title">Servers</span>
99102
<select onChange={ this.onServerChange }>
100103
{ servers.valueSeq().map(
101104
( server ) =>
@@ -109,13 +112,14 @@ export default class Servers extends React.Component {
109112
</label>
110113
{ shouldShowVariableUI ?
111114
<div>
112-
<h4>Server variables</h4>
115+
113116
<div className={"computed-url"}>
114117
Computed URL:
115118
<code>
116119
{getEffectiveServerValue(currentServer)}
117120
</code>
118121
</div>
122+
<h4>Server variables</h4>
119123
<table>
120124
<tbody>
121125
{

src/core/plugins/oas3/reducers.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import {
77
} from "./actions"
88

99
export default {
10-
[UPDATE_SELECTED_SERVER]: (state, { payload: selectedServerUrl } ) =>{
11-
return state.setIn( [ "selectedServer" ], selectedServerUrl)
10+
[UPDATE_SELECTED_SERVER]: (state, { payload: { selectedServerUrl, namespace } } ) =>{
11+
const path = namespace ? [ namespace, "selectedServer"] : [ "selectedServer"]
12+
return state.setIn( path, selectedServerUrl)
1213
},
1314
[UPDATE_REQUEST_BODY_VALUE]: (state, { payload: { value, pathMethod } } ) =>{
1415
let [path, method] = pathMethod
@@ -21,7 +22,8 @@ export default {
2122
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, path, method } } ) =>{
2223
return state.setIn( [ "requestData", path, method, "responseContentType" ], value)
2324
},
24-
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{
25-
return state.setIn( [ "serverVariableValues", server, key ], val)
25+
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, namespace, key, val } } ) =>{
26+
const path = namespace ? [ namespace, "serverVariableValues", server, key ] : [ "serverVariableValues", server, key ]
27+
return state.setIn(path, val)
2628
},
2729
}

src/core/plugins/oas3/selectors.js

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ function onlyOAS3(selector) {
1515
}
1616
}
1717

18-
export const selectedServer = onlyOAS3(state => {
19-
return state.getIn(["selectedServer"]) || ""
18+
export const selectedServer = onlyOAS3((state, namespace) => {
19+
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
20+
return state.getIn(path) || ""
2021
}
2122
)
2223

@@ -35,19 +36,68 @@ export const responseContentType = onlyOAS3((state, path, method) => {
3536
}
3637
)
3738

38-
export const serverVariableValue = onlyOAS3((state, server, key) => {
39-
return state.getIn(["serverVariableValues", server, key]) || null
39+
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
40+
let path
41+
42+
// locationData may take one of two forms, for backwards compatibility
43+
// Object: ({server, namespace?}) or String:(server)
44+
if(typeof locationData !== "string") {
45+
const { server, namespace } = locationData
46+
if(namespace) {
47+
path = [namespace, "serverVariableValues", server, key]
48+
} else {
49+
path = ["serverVariableValues", server, key]
50+
}
51+
} else {
52+
const server = locationData
53+
path = ["serverVariableValues", server, key]
54+
}
55+
56+
return state.getIn(path) || null
4057
}
4158
)
4259

43-
export const serverVariables = onlyOAS3((state, server) => {
44-
return state.getIn(["serverVariableValues", server]) || OrderedMap()
60+
export const serverVariables = onlyOAS3((state, locationData) => {
61+
let path
62+
63+
// locationData may take one of two forms, for backwards compatibility
64+
// Object: ({server, namespace?}) or String:(server)
65+
if(typeof locationData !== "string") {
66+
const { server, namespace } = locationData
67+
if(namespace) {
68+
path = [namespace, "serverVariableValues", server]
69+
} else {
70+
path = ["serverVariableValues", server]
71+
}
72+
} else {
73+
const server = locationData
74+
path = ["serverVariableValues", server]
75+
}
76+
77+
return state.getIn(path) || OrderedMap()
4578
}
4679
)
4780

48-
export const serverEffectiveValue = onlyOAS3((state, server) => {
49-
let varValues = state.getIn(["serverVariableValues", server]) || OrderedMap()
50-
let str = server
81+
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
82+
var varValues, serverValue
83+
84+
// locationData may take one of two forms, for backwards compatibility
85+
// Object: ({server, namespace?}) or String:(server)
86+
if(typeof locationData !== "string") {
87+
const { server, namespace } = locationData
88+
serverValue = server
89+
if(namespace) {
90+
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
91+
} else {
92+
varValues = state.getIn(["serverVariableValues", serverValue])
93+
}
94+
} else {
95+
serverValue = locationData
96+
varValues = state.getIn(["serverVariableValues", serverValue])
97+
}
98+
99+
varValues = varValues || OrderedMap()
100+
let str = serverValue
51101

52102
varValues.map((val, key) => {
53103
str = str.replace(new RegExp(`{${key}}`, "g"), val)

src/core/plugins/spec/actions.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,18 @@ export const executeRequest = (req) =>
228228
}
229229

230230
if(specSelectors.isOAS3()) {
231-
// OAS3 request feature support
232-
req.server = oas3Selectors.selectedServer()
233-
req.serverVariables = oas3Selectors.serverVariables(req.server).toJS()
231+
const namespace = `${pathName}:${method}`
232+
233+
req.server = oas3Selectors.selectedServer(namespace) || oas3Selectors.selectedServer()
234+
235+
const namespaceVariables = oas3Selectors.serverVariables({
236+
server: req.server,
237+
namespace
238+
}).toJS()
239+
const globalVariables = oas3Selectors.serverVariables({ server: req.server }).toJS()
240+
241+
req.serverVariables = Object.keys(namespaceVariables).length ? namespaceVariables : globalVariables
242+
234243
req.requestContentType = oas3Selectors.requestContentType(pathName, method)
235244
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
236245
const requestBody = oas3Selectors.requestBodyValue(pathName, method)

0 commit comments

Comments
 (0)