Compare commits

...
100 Commits
Author SHA1 Message Date
kyle f1f29aa7e1 Merge pull request #3974 from shockey/v/3.6.0
v3.6.0
2017-12-02 00:02:29 -08:00
Kyle Shockey cdf3dfa075 v3.6.0 2017-12-01 23:50:48 -08:00
kyle 8f73519cc7 Merge pull request #3957 from mrparkers/base-url
Allow UI base url to be customizable
2017-12-01 23:50:28 -08:00
kyle 3ee4f8d6e3 Merge branch 'master' into base-url 2017-12-01 22:20:57 -08:00
kyle 213f6d7080 Merge pull request #3967 from daniel-smartbear/feature/add-type-example-for-headers
Feature/add type example for headers
2017-12-01 22:12:48 -08:00
kyle 7254e8b3fa Merge branch 'master' into feature/add-type-example-for-headers 2017-12-01 22:06:16 -08:00
Michael Parker 13eed0d0f7 Merge branch 'master' into base-url 2017-12-01 09:31:48 -06:00
kyle 0256b97855 Merge pull request #3972 from shockey/ft/3820-oas3-path-operation-servers
OAS3: Path & Operation Servers
2017-11-30 23:21:31 -08:00
kyle 61eb86ed50 Merge branch 'master' into ft/3820-oas3-path-operation-servers 2017-11-30 23:12:11 -08:00
Kyle Shockey bb57fd2406 Send server variables to Client as JS objects 2017-11-30 20:11:30 -08:00
Kyle Shockey 6f5649c6ba Only set the first server as current if we...
...don't already have a currentServer.

This avoids having the selected server reset each time the
operation is expanded, or the Try-It-Out mode is entered.
2017-11-30 17:28:35 -08:00
Kyle Shockey d7d061b5af Provide operation server data to Swagger-Client 2017-11-30 17:26:49 -08:00
Kyle Shockey 0f86524514 Don't render if there are no servers defined 2017-11-30 17:11:49 -08:00
Kyle Shockey ba90c70b34 LESS CSS BUGS 2017-11-30 17:10:25 -08:00
Kyle Shockey ef3ccd7a23 Move server styles into its own scss file; add a little polish 2017-11-30 17:06:17 -08:00
Kyle Shockey 0c0c9a6519 LESS bugs 2017-11-30 16:49:26 -08:00
Kyle Shockey 945d7a3a0f Basic OperationServers wireup 2017-11-30 16:34:36 -08:00
Kyle Shockey b3c549055d Remove describe.only 2017-11-30 15:58:26 -08:00
Kyle Shockey efd02106a2 Support namespaces in OAS3 server state 2017-11-30 15:57:37 -08:00
Kyle Shockey 7e9d8f0b37 Wire up OperationServers passthrough 2017-11-30 15:30:46 -08:00
Kyle Shockey ab7af75ab4 Add OAS3 state tests 2017-11-30 15:30:37 -08:00
Kyle Shockey 5d3efbb5f7 Display option level information in message, not header 2017-11-30 14:37:26 -08:00
Kyle Shockey 0997c5e5d4 Remove hardwired "Server" header, make global one prettier 2017-11-30 14:34:01 -08:00
Kyle Shockey 21ff236e43 Basic OperationServers display 2017-11-30 14:25:05 -08:00
Kyle Shockey 07a9410ee5 Create OperationServers component 2017-11-30 14:07:42 -08:00
Kyle Shockey 25b9fb28dc Move Server Variables header to a more sensible location 2017-11-30 13:50:39 -08:00
daniel-smartbear 9603905d1d fix for swagger-2 header type not showing 2017-11-30 10:55:17 +00:00
daniel-smartbear a7a50b8457 slight changes to header code 2017-11-30 10:55:17 +00:00
daniel-smartbear 00a059b8dd fix response header type not showing, and displaying example below if theres one present 2017-11-30 10:55:17 +00:00
kyle d003df2e5a Merge branch 'master' into base-url 2017-11-29 23:48:02 -06:00
kyle 50153487ba Merge pull request #3965 from shockey/bug/oauth2-authorization-interceptor
Bug/oauth2 authorization interceptor
2017-11-29 23:46:52 -06:00
kyle d5a4cab383 Merge branch 'master' into bug/oauth2-authorization-interceptor 2017-11-29 21:06:57 -06:00
Kyle Shockey e6ecb201c7 Update interceptor documentation 2017-11-29 21:06:25 -06:00
kyle ec787cfeb6 Merge pull request #3964 from shockey/bug/3949-enum-selectable-values
Bug/3949 enum selectable values
2017-11-29 19:53:09 -06:00
kyle 67132ca920 Merge branch 'master' into bug/3949-enum-selectable-values 2017-11-29 19:45:36 -06:00
Kyle Shockey 0fa532d35c Ensure that unknown types are always displayed as strings 2017-11-29 19:41:12 -06:00
Kyle Shockey 15cf495452 Wrap ternary operator in parens to ensure correct flow 2017-11-29 19:27:51 -06:00
Kyle Shockey 5224932cf9 Fix failing test 2017-11-29 19:21:20 -06:00
Kyle Shockey 8d1d15ca4a Simplify JsonSchemaform getComponent logic 2017-11-29 19:04:50 -06:00
Kyle Shockey e17a5f40f5 Add JsonSchemaForm tests, including one failing 2017-11-29 19:03:40 -06:00
Kyle Shockey 2325118540 Add responseInterceptor as well 2017-11-29 15:55:15 -06:00
Kyle Shockey ade47ca40e Add requestInterceptor to OAuth2 request authorization calls 2017-11-29 15:54:17 -06:00
Michael Parker 8223710e92 Merge branch 'master' into base-url 2017-11-29 08:22:43 -06:00
kyle de7e0910bb Merge pull request #3959 from shockey/bug/oas3-parameter-without-schema
Correctly validate OAS3 parameters that lack a `schema`
2017-11-28 22:59:31 -06:00
kyle 713d1a1bb8 Merge branch 'master' into bug/oas3-parameter-without-schema 2017-11-28 22:23:17 -06:00
Kyle Shockey 40bd720eb4 Correctly validate OAS3 parameters that lack a schema 2017-11-28 22:19:53 -06:00
Michael Parker a6dd9d60e7 Add documentation to README 2017-11-28 13:22:34 -06:00
Michael Parker 5db4131046 Allow UI base url to be customizable 2017-11-28 12:01:49 -06:00
kyle 52693254e9 Merge pull request #3895 from conorlennon/master
Remove checking that the response has a content-length for download links
2017-11-28 00:49:32 -06:00
conorlennon 51a68c0d8e Merge branch 'master' into master 2017-11-24 08:11:03 +00:00
kyle 91e7ade059 Merge pull request #3945 from shockey/v/3.5.0
v3.5.0
2017-11-23 11:01:28 -08:00
Kyle Shockey 88e98ce281 fix tests 2017-11-23 12:55:29 -06:00
Kyle Shockey 6bb5a95424 Rebuild dist 2017-11-23 12:52:28 -06:00
Kyle Shockey 23fd8a4d73 v3.5.0 2017-11-23 12:50:08 -06:00
Kyle Shockey 640050e54e Add spacing between done and authorize button 2017-11-23 12:35:00 -06:00
Kyle Shockey c70e0f8c38 Display object model extensions correctly 2017-11-23 12:28:37 -06:00
Kyle Shockey b42e2a7045 Render non-primitive extension values more reliably 2017-11-23 11:58:46 -06:00
conorlennon 469b4d6323 Merge branch 'master' into master 2017-11-23 07:51:16 +00:00
kyle d3cc636dde Merge pull request #3868 from thompsongl/ft/3052-extensions
parameter & operation extensions display
2017-11-22 22:30:50 -08:00
kyle 32ff344bdd Adjust formatting of method calls 2017-11-23 00:22:48 -06:00
kyle 40f8481127 Merge branch 'master' into ft/3052-extensions 2017-11-22 22:16:21 -08:00
kyle 7b13f41be7 Merge pull request #3938 from thompsongl/bug/3936-externaldocs
bug/3936-externaldocs
2017-11-22 21:10:04 -08:00
kyle 7f237f3b23 Merge branch 'master' into bug/3936-externaldocs 2017-11-22 20:38:35 -08:00
kyle dc7706e262 Merge pull request #3929 from k42b3/master
Add flow to make scope checkbox id unqiue
2017-11-22 12:25:47 -08:00
kyle 20cf8a3b1b Merge branch 'master' into master 2017-11-22 12:22:09 -08:00
conorlennon f697e45362 Merge branch 'master' into master 2017-11-22 07:53:26 +00:00
kyle 4f13d6dda6 Merge pull request #3939 from swagger-api/ft/authmodelclosebtn
Auth modal close button addded
2017-11-21 14:57:46 -08:00
kyle 1695f655bb Merge branch 'master' into ft/authmodelclosebtn 2017-11-21 14:53:38 -08:00
kyle dc29e06d66 Merge pull request #3942 from shockey/master
Include `dist/oauth2-redirect.html` in `swagger-ui` module
2017-11-21 14:53:11 -08:00
Kyle Shockey be8ce8688e Reset dist 2017-11-21 14:49:41 -08:00
Kyle Shockey ef256de050 Include dist/oauth2-redirect.html in swagger-ui module 2017-11-21 14:44:54 -08:00
kyle 01d84cdc0f Merge pull request #3941 from shockey/bug/3932-schema-not-values
Don't treat `not` as an array (in contrast to `allOf`, `anyOf`, `oneOf`)
2017-11-21 14:33:29 -08:00
kyle 9f18e02ace Merge branch 'master' into bug/3932-schema-not-values 2017-11-21 14:22:21 -08:00
Kyle Shockey 44d9234971 Don't treat not as an array (in contrast to allOf, anyOf) 2017-11-21 14:08:55 -08:00
Greg Thompson 88eda43c46 resolve #3644 while in the file 2017-11-21 13:43:29 -06:00
Minasokoni a7818d5983 Auth modal close button addded 2017-11-21 14:10:22 -05:00
Greg Thompson a2f09896f7 stop using immutable getters for js obj 2017-11-21 12:50:37 -06:00
Greg Thompson 04daadafd5 Merge branch 'master' into ft/3052-extensions 2017-11-21 09:15:50 -06:00
conorlennon 3c2af93589 Merge branch 'master' into master 2017-11-21 08:20:35 +00:00
kyle cfc7b1a192 Merge pull request #3930 from floriantraber/bug/3571-oas-3.0-doesnt-render-in-ie11-startsWith-function-missing
Fixes #3571 - add polyfill for startsWith function for IE11.
2017-11-20 15:17:15 -08:00
Greg Thompson 8ff2d77398 Merge branch 'master' into ft/3052-extensions 2017-11-20 09:48:33 -06:00
conorlennon 7c1126ce51 Merge branch 'master' into master 2017-11-20 07:58:09 +00:00
Florian Traber e2d0bd7628 Fixes #3571 - add polyfill for startsWith function for IE11. 2017-11-18 17:21:24 +01:00
Christoph Kappestein 774acb1f28 add flow to make scope checkbox id unqiue 2017-11-18 09:59:15 +01:00
Greg Thompson 31694d7533 Merge branch 'master' into ft/3052-extensions 2017-11-17 11:00:43 -06:00
conorlennon 2831c59e70 Merge branch 'master' into master 2017-11-17 09:37:35 +00:00
Greg Thompson 0d0b3279bb Merge branch 'master' into ft/3052-extensions 2017-11-13 09:29:19 -06:00
Conor Lennon f929d4fdd6 Remove check that the response has a content-length when making a
download link available.
2017-11-12 20:35:15 +00:00
Greg Thompson 40c2c28a7d add showExtensions to config table 2017-11-09 10:44:30 -06:00
Greg Thompson ee5d9a8c34 propType test fix 2017-11-09 10:23:02 -06:00
Greg Thompson 91dab7b166 getConfigs prop expansion; limit extension render based on config setting 2017-11-09 10:22:41 -06:00
Greg Thompson 83dd9f3dfc showExtensions config param 2017-11-09 10:21:08 -06:00
Greg Thompson 7b83f64676 Merge branch 'master' into ft/3052-extensions 2017-11-09 08:31:04 -06:00
Greg Thompson 233dacde71 Merge branch 'ft/3052-extensions' of https://github.com/thompsongl/swagger-ui into ft/3052-extensions 2017-11-08 08:52:55 -06:00
Greg Thompson 45a0295c0e use correct immutable map size 2017-11-08 08:52:34 -06:00
kyle 5231c13579 Merge branch 'master' into ft/3052-extensions 2017-11-07 21:33:05 -08:00
Greg Thompson a58cd25f08 Merge branch 'master' into ft/3052-extensions 2017-11-06 09:18:51 -06:00
Greg Thompson fc3ac17710 imports 2017-11-06 09:18:16 -06:00
Greg Thompson 9a66acf37f operation extensions display 2017-11-06 09:18:05 -06:00
Greg Thompson 44c422eba3 parameter extensions display 2017-11-06 09:17:30 -06:00
56 changed files with 1086 additions and 183 deletions
+1
View File
@@ -6,3 +6,4 @@
!dist/swagger-ui.js.map
!dist/swagger-ui.css
!dist/swagger-ui.css.map
!dist/oauth2-redirect.html
+1
View File
@@ -13,6 +13,7 @@ ENV OAUTH_APP_NAME "**None**"
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
ENV SWAGGER_JSON "/app/swagger.json"
ENV PORT 80
ENV BASE_URL ""
RUN apk add --update nginx
RUN mkdir -p /run/nginx
+12 -3
View File
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | -----
3.4.5 | 2017-11-03 | 2.0, 3.0 | [tag v3.4.5](https://github.com/swagger-api/swagger-ui/tree/v3.4.5)
3.6.0 | 2017-12-01 | 2.0, 3.0 | [tag v3.5=6.0](https://github.com/swagger-api/swagger-ui/tree/v3.6.0)
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
@@ -49,6 +49,14 @@ Or you can provide your own swagger.json on your host
docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
The base URL of the web application can be changed by specifying the `BASE_URL` environment variable:
```
docker run -p 80:8080 -e BASE_URL=/swagger -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
```
This will serve Swagger UI at `/swagger` instead of `/`.
##### Prerequisites
- Node 6.x
- NPM 3.x
@@ -162,9 +170,10 @@ displayRequestDuration | Controls the display of the request duration (in millis
maxDisplayedTags | If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations.
filter | If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be true/false to enable or disable, or an explicit filter string in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
deepLinking | If set to `true`, enables dynamic deep linking for tags and operations. [Docs](https://github.com/swagger-api/swagger-ui/blob/master/docs/deep-linking.md)
requestInterceptor | MUST be a function. Function to intercept try-it-out requests. Accepts one argument requestInterceptor(request) and must return the potentially modified request.
responseInterceptor | MUST be a function. Function to intercept try-it-out responses. Accepts one argument responseInterceptor(response) and must return the potentially modified response.
requestInterceptor | MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 requests. Accepts one argument requestInterceptor(request) and must return the potentially modified request.
responseInterceptor | MUST be a function. Function to intercept remote definition, Try-It-Out, and OAuth2 responses. Accepts one argument responseInterceptor(response) and must return the potentially modified response.
showMutatedRequest | If set to `true` (the default), uses the mutated request returned from a rquestInterceptor to produce the curl command in the UI, otherwise the request before the requestInterceptor was applied is used.
showExtensions | Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema. The default is `false`.
### Plugins
+15 -15
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+10
View File
@@ -21,6 +21,16 @@ replace_or_delete_in_index () {
fi
}
if [ "${BASE_URL}" ]; then
NGINX_WITH_BASE_URL="${NGINX_ROOT}${BASE_URL}"
mkdir -p ${NGINX_WITH_BASE_URL}
mv ${NGINX_ROOT}/*.* ${NGINX_WITH_BASE_URL}/
INDEX_FILE=$NGINX_WITH_BASE_URL/index.html
NGINX_ROOT=$NGINX_WITH_BASE_URL
fi
replace_in_index myApiKeyXXXX123456789 $API_KEY
replace_or_delete_in_index your-client-id $OAUTH_CLIENT_ID
replace_or_delete_in_index your-client-secret-if-required $OAUTH_CLIENT_SECRET
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.4.5",
"version": "3.6.0",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -81,7 +81,7 @@
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.3.4",
"swagger-client": "^3.4.0",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
+3 -2
View File
@@ -7,6 +7,7 @@ export default class ArrayModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
required: PropTypes.bool,
@@ -15,7 +16,7 @@ export default class ArrayModel extends Component {
}
render(){
let { getComponent, schema, depth, expandDepth, name } = this.props
let { getComponent, getConfigs, schema, depth, expandDepth, name } = this.props
let description = schema.get("description")
let items = schema.get("items")
let title = schema.get("title") || name
@@ -46,7 +47,7 @@ export default class ArrayModel extends Component {
!description ? null :
<Markdown source={ description } />
}
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
<span><Model { ...this.props } getConfigs={ getConfigs } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
]
</ModelCollapse>
</span>
+8
View File
@@ -41,6 +41,13 @@ export default class Auths extends React.Component {
authActions.logout(auths)
}
close =(e) => {
e.preventDefault()
let { authActions } = this.props
authActions.showDefinitions(false)
}
render() {
let { definitions, getComponent, authSelectors, errSelectors } = this.props
const AuthItem = getComponent("AuthItem")
@@ -74,6 +81,7 @@ export default class Auths extends React.Component {
}).toArray()
}
<div className="auth-btn-wrapper">
<Button className="btn modal-btn auth btn-done" onClick={ this.close }>Done</Button>
{
nonOauthDefinitions.size === authorizedAuth.size ? <Button className="btn modal-btn auth" onClick={ this.logoutClick }>Logout</Button>
: <Button type="submit" className="btn modal-btn auth authorize">Authorize</Button>
+2 -2
View File
@@ -200,11 +200,11 @@ export default class Oauth2 extends React.Component {
<Row key={ name }>
<div className="checkbox">
<Input data-value={ name }
id={`${name}-checkbox-${this.state.name}`}
id={`${name}-${flow}-checkbox-${this.state.name}`}
disabled={ isAuthorized }
type="checkbox"
onChange={ this.onScopeChange }/>
<label htmlFor={`${name}-checkbox-${this.state.name}`}>
<label htmlFor={`${name}-${flow}-checkbox-${this.state.name}`}>
<span className="item"></span>
<div className="text">
<p className="name">{name}</p>
+11 -4
View File
@@ -2,20 +2,24 @@ import React from "react"
import PropTypes from "prop-types"
import Im from "immutable"
const propStyle = { color: "#999", fontStyle: "italic" }
export default class Headers extends React.Component {
static propTypes = {
headers: PropTypes.object.isRequired
headers: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
};
render() {
let { headers } = this.props
let { headers, getComponent } = this.props
const Property = getComponent("Property")
if ( !headers || !headers.size )
return null
return (
return (
<div className="headers-wrapper">
<h4 className="headers__title">Headers:</h4>
<table className="headers">
@@ -32,10 +36,13 @@ export default class Headers extends React.Component {
if(!Im.Map.isMap(header)) {
return null
}
const type = header.getIn(["schema"]) ? header.getIn(["schema", "type"]) : header.getIn(["type"])
const schemaExample = header.getIn(["schema", "example"])
return (<tr key={ key }>
<td className="header-col">{ key }</td>
<td className="header-col">{ header.get( "description" ) }</td>
<td className="header-col">{ header.get( "type" ) }</td>
<td className="header-col">{ type } { schemaExample ? <Property propKey={ "Example" } propVal={ schemaExample } propStyle={ propStyle } /> : null }</td>
</tr>)
}).toArray()
}
+1 -1
View File
@@ -183,7 +183,7 @@ export class Select extends React.Component {
{ allowEmptyValue ? <option value="">--</option> : null }
{
allowedValues.map(function (item, key) {
return <option key={ key } value={ String(item) }>{ item }</option>
return <option key={ key } value={ String(item) }>{ String(item) }</option>
})
}
</select>
+2 -1
View File
@@ -94,8 +94,9 @@ export default class BaseLayout extends React.Component {
) : null }
{ servers && servers.size ? (
<div className="server-container">
<div className="global-server-container">
<Col className="servers wrapper" mobile={12}>
<span className="servers-title">Server</span>
<Servers
servers={servers}
currentServer={oas3Selectors.selectedServer()}
+1
View File
@@ -52,6 +52,7 @@ export default class ModelExample extends React.Component {
{
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
expandDepth={ defaultModelExpandDepth } />
+3 -4
View File
@@ -6,18 +6,17 @@ export default class ModelComponent extends Component {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
expandDepth: PropTypes.number
}
render(){
let { getComponent } = this.props
let { getComponent, getConfigs } = this.props
const Model = getComponent("Model")
return <div className="model-box">
<Model { ...this.props } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
<Model { ...this.props } getConfigs={ getConfigs } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
</div>
}
}
+7 -2
View File
@@ -1,10 +1,12 @@
import React, { PureComponent } from "react"
import ImPropTypes from "react-immutable-proptypes"
import PropTypes from "prop-types"
export default class Model extends PureComponent {
static propTypes = {
schema: PropTypes.object.isRequired,
schema: ImPropTypes.orderedMap.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
@@ -29,7 +31,7 @@ export default class Model extends PureComponent {
}
render () {
let { getComponent, specSelectors, schema, required, name, isRef } = this.props
let { getComponent, getConfigs, specSelectors, schema, required, name, isRef } = this.props
const ObjectModel = getComponent("ObjectModel")
const ArrayModel = getComponent("ArrayModel")
const PrimitiveModel = getComponent("PrimitiveModel")
@@ -53,6 +55,7 @@ export default class Model extends PureComponent {
case "object":
return <ObjectModel
className="object" { ...this.props }
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}
@@ -60,6 +63,7 @@ export default class Model extends PureComponent {
case "array":
return <ArrayModel
className="array" { ...this.props }
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}
@@ -72,6 +76,7 @@ export default class Model extends PureComponent {
return <PrimitiveModel
{ ...this.props }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}
+1
View File
@@ -36,6 +36,7 @@ export default class Models extends Component {
expandDepth={ defaultModelExpandDepth }
schema={ model }
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }/>
</div>
}).toArray()
+40 -7
View File
@@ -9,6 +9,7 @@ export default class ObjectModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
@@ -17,7 +18,7 @@ export default class ObjectModel extends Component {
}
render(){
let { schema, name, isRef, getComponent, depth, expandDepth, ...otherProps } = this.props
let { schema, name, isRef, getComponent, getConfigs, depth, expandDepth, ...otherProps } = this.props
let { specSelectors } = otherProps
let { isOAS3 } = specSelectors
@@ -25,6 +26,8 @@ export default class ObjectModel extends Component {
return null
}
const { showExtensions } = getConfigs()
let description = schema.get("description")
let properties = schema.get("properties")
let additionalProperties = schema.get("additionalProperties")
@@ -91,12 +94,37 @@ export default class ObjectModel extends Component {
<Model key={ `object-${name}-${key}_${value}` } { ...otherProps }
required={ isRequired }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ value }
depth={ depth + 1 } />
</td>
</tr>)
}).toArray()
}
{
// empty row befor extensions...
!showExtensions ? null : <tr>&nbsp;</tr>
}
{
!showExtensions ? null :
schema.entrySeq().map(
([key, value]) => {
if(key.slice(0,2) !== "x-") {
return
}
const normalizedValue = !value ? null : value.toJS ? value.toJS() : value
return (<tr key={key} style={{ color: "#777" }}>
<td>
{ key }
</td>
<td style={{ verticalAlign: "top" }}>
{ JSON.stringify(normalizedValue) }
</td>
</tr>)
}).toArray()
}
{
!additionalProperties || !additionalProperties.size ? null
: <tr>
@@ -104,6 +132,7 @@ export default class ObjectModel extends Component {
<td>
<Model { ...otherProps } required={ false }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ additionalProperties }
depth={ depth + 1 } />
</td>
@@ -117,6 +146,7 @@ export default class ObjectModel extends Component {
{anyOf.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
})}
@@ -131,6 +161,7 @@ export default class ObjectModel extends Component {
{oneOf.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
})}
@@ -142,12 +173,14 @@ export default class ObjectModel extends Component {
: <tr>
<td>{ "not ->" }</td>
<td>
{not.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
schema={ schema }
depth={ depth + 1 } /></div>
})}
<div>
<Model { ...otherProps }
required={ false }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ not }
depth={ depth + 1 } />
</div>
</td>
</tr>
}
@@ -0,0 +1,17 @@
import React from "react"
import PropTypes from "prop-types"
export const OperationExtRow = ({ xKey, xVal }) => {
const xNormalizedValue = !xVal ? null : xVal.toJS ? xVal.toJS() : xVal
return (<tr>
<td>{ xKey }</td>
<td>{ JSON.stringify(xNormalizedValue) }</td>
</tr>)
}
OperationExtRow.propTypes = {
xKey: PropTypes.string,
xVal: PropTypes.any
}
export default OperationExtRow
@@ -0,0 +1,35 @@
import React from "react"
import PropTypes from "prop-types"
export const OperationExt = ({ extensions, getComponent }) => {
let OperationExtRow = getComponent("OperationExtRow")
return (
<div className="opblock-section">
<div className="opblock-section-header">
<h4>Extensions</h4>
</div>
<div className="table-container">
<table>
<thead>
<tr>
<td className="col col_header">Field</td>
<td className="col col_header">Value</td>
</tr>
</thead>
<tbody>
{
extensions.entrySeq().map(([k, v]) => <OperationExtRow key={`${k}-${v}`} xKey={k} xVal={v} />)
}
</tbody>
</table>
</div>
</div>
)
}
OperationExt.propTypes = {
extensions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
export default OperationExt
+32 -5
View File
@@ -1,7 +1,7 @@
import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { getList } from "core/utils"
import { sanitizeUrl } from "core/utils"
import { getExtensions, sanitizeUrl } from "core/utils"
import { Iterable } from "immutable"
export default class Operation extends PureComponent {
@@ -22,6 +22,7 @@ export default class Operation extends PureComponent {
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
oas3Selectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired
@@ -48,7 +49,8 @@ export default class Operation extends PureComponent {
specSelectors,
authActions,
authSelectors,
oas3Actions
oas3Actions,
oas3Selectors
} = this.props
let operationProps = this.props.operation
@@ -85,6 +87,7 @@ export default class Operation extends PureComponent {
let parameters = getList(operation, ["parameters"])
let operationScheme = specSelectors.operationScheme(path, method)
let isShownKey = ["operations", tag, operationId]
let extensions = getExtensions(operation)
const Responses = getComponent("responses")
const Parameters = getComponent( "parameters" )
@@ -95,6 +98,10 @@ export default class Operation extends PureComponent {
const Collapse = getComponent( "Collapse" )
const Markdown = getComponent( "Markdown" )
const Schemes = getComponent( "schemes" )
const OperationServers = getComponent( "OperationServers" )
const OperationExt = getComponent( "OperationExt" )
const { showExtensions } = getConfigs()
// Merge in Live Response
if(responses && response && response.size > 0) {
@@ -149,17 +156,18 @@ export default class Operation extends PureComponent {
</div>
}
{
externalDocs && externalDocs.get("url") ?
externalDocs && externalDocs.url ?
<div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs">
<span className="opblock-external-docs__description">
<Markdown source={ externalDocs.get("description") } />
<Markdown source={ externalDocs.description } />
</span>
<a className="opblock-external-docs__link" href={ sanitizeUrl(externalDocs.get("url")) }>{ externalDocs.get("url") }</a>
<a target="_blank" className="opblock-external-docs__link" href={ sanitizeUrl(externalDocs.url) }>{ externalDocs.url }</a>
</div>
</div> : null
}
<Parameters
parameters={parameters}
operation={operation}
@@ -177,6 +185,21 @@ export default class Operation extends PureComponent {
getConfigs={ getConfigs }
/>
{ !tryItOutEnabled ? null :
<OperationServers
getComponent={getComponent}
path={path}
method={method}
operationServers={operation.get("servers")}
pathServers={specSelectors.paths().getIn([path, "servers"])}
getSelectedServer={oas3Selectors.selectedServer}
setSelectedServer={oas3Actions.setSelectedServer}
setServerVariableValue={oas3Actions.setServerVariableValue}
getServerVariable={oas3Selectors.serverVariableValue}
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
/>
}
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
<Schemes schemes={ schemes }
path={ path }
@@ -225,6 +248,10 @@ export default class Operation extends PureComponent {
displayRequestDuration={ displayRequestDuration }
fn={fn} />
}
{ !showExtensions || !extensions.size ? null :
<OperationExt extensions={ extensions } getComponent={ getComponent } />
}
</div>
</Collapse>
</div>
@@ -0,0 +1,12 @@
import React from "react"
import PropTypes from "prop-types"
export const ParameterExt = ({ xKey, xVal }) => {
return <div className="parameter__extension">{ xKey }: { String(xVal) }</div>
}
ParameterExt.propTypes = {
xKey: PropTypes.string,
xVal: PropTypes.any
}
export default ParameterExt
+6
View File
@@ -2,6 +2,7 @@ import React, { Component } from "react"
import { Map } from "immutable"
import PropTypes from "prop-types"
import win from "core/window"
import { getExtensions } from "core/utils"
export default class ParameterRow extends Component {
static propTypes = {
@@ -72,6 +73,8 @@ export default class ParameterRow extends Component {
let { isOAS3 } = specSelectors
const { showExtensions } = getConfigs()
// const onChangeWrapper = (value) => onChange(param, value)
const JsonSchemaForm = getComponent("JsonSchemaForm")
const ParamBody = getComponent("ParamBody")
@@ -91,6 +94,7 @@ export default class ParameterRow extends Component {
const ModelExample = getComponent("modelExample")
const Markdown = getComponent("Markdown")
const ParameterExt = getComponent("ParameterExt")
let schema = param.get("schema")
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
@@ -100,6 +104,7 @@ export default class ParameterRow extends Component {
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 extensions = getExtensions(param)
return (
<tr>
@@ -113,6 +118,7 @@ export default class ParameterRow extends Component {
{ isOAS3 && isOAS3() && param.get("deprecated") ? "deprecated": null }
</div>
<div className="parameter__in">({ param.get("in") })</div>
{ !showExtensions || !extensions.size ? null : extensions.map((v, key) => <ParameterExt key={`${key}-${v}`} xKey={key} xVal={v} /> )}
</td>
<td className="col parameters-col_description">
+12 -2
View File
@@ -1,5 +1,6 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import { getExtensions } from "core/utils"
const propStyle = { color: "#999", fontStyle: "italic" }
@@ -7,12 +8,15 @@ export default class Primitive extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
name: PropTypes.string,
depth: PropTypes.number
}
render(){
let { schema, getComponent, name, depth } = this.props
let { schema, getComponent, getConfigs, name, depth } = this.props
const { showExtensions } = getConfigs()
if(!schema || !schema.get) {
// don't render if schema isn't correctly formed
@@ -25,7 +29,10 @@ export default class Primitive extends Component {
let enumArray = schema.get("enum")
let title = schema.get("title") || name
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
let extensions = getExtensions(schema)
let properties = schema
.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
.filterNot( (v, key) => extensions.has(key) )
const Markdown = getComponent("Markdown")
const EnumModel = getComponent("EnumModel")
const Property = getComponent("Property")
@@ -38,6 +45,9 @@ export default class Primitive extends Component {
{
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null
}
{
showExtensions && extensions.size ? extensions.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null
}
{
!description ? null :
<Markdown source={ description } />
-3
View File
@@ -57,9 +57,6 @@ export default class ResponseBody extends React.Component {
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
let contentLength = headers["content-length"] || headers["Content-Length"]
if ( !(+contentLength) ) return null
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
if (!isSafari && "Blob" in window) {
+4 -1
View File
@@ -153,7 +153,10 @@ export default class Response extends React.Component {
) : null}
{ headers ? (
<Headers headers={ headers }/>
<Headers
headers={ headers }
getComponent={ getComponent }
/>
) : null}
@@ -35,6 +35,7 @@ export default class OperationContainer extends PureComponent {
getComponent: PropTypes.func.isRequired,
authActions: PropTypes.object,
oas3Actions: PropTypes.object,
oas3Selectors: PropTypes.object,
authSelectors: PropTypes.object,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
@@ -149,6 +150,7 @@ export default class OperationContainer extends PureComponent {
authActions,
authSelectors,
oas3Actions,
oas3Selectors,
fn
} = this.props
@@ -189,6 +191,7 @@ export default class OperationContainer extends PureComponent {
specActions={ specActions }
specSelectors={ specSelectors }
oas3Actions={oas3Actions}
oas3Selectors={oas3Selectors}
layoutActions={ layoutActions }
layoutSelectors={ layoutSelectors }
authActions={ authActions }
+1
View File
@@ -46,6 +46,7 @@ module.exports = function SwaggerUI(opts) {
showMutatedRequest: true,
defaultModelRendering: "example",
defaultModelExpandDepth: 1,
showExtensions: false,
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
+11 -11
View File
@@ -36,7 +36,7 @@ export class JsonSchemaForm extends Component {
let { type, format="" } = schema
let Comp = getComponent(`JsonSchema_${type}_${format}`) || getComponent(`JsonSchema_${type}`) || getComponent("JsonSchema_string")
let Comp = (format ? getComponent(`JsonSchema_${type}_${format}`) : getComponent(`JsonSchema_${type}`)) || getComponent("JsonSchema_string")
return <Comp { ...this.props } fn={fn} getComponent={getComponent} value={value} onChange={onChange} schema={schema}/>
}
@@ -68,19 +68,19 @@ export class JsonSchema_string extends Component {
const isDisabled = schema["in"] === "formData" && !("FormData" in window)
const Input = getComponent("Input")
if (schema["type"] === "file") {
return (<Input type="file"
className={ errors.length ? "invalid" : ""}
return (<Input type="file"
className={ errors.length ? "invalid" : ""}
title={ errors.length ? errors : ""}
onChange={ this.onChange }
onChange={ this.onChange }
disabled={isDisabled}/>)
}
else {
return (<Input type={ schema.format === "password" ? "password" : "text" }
className={ errors.length ? "invalid" : ""}
return (<Input type={ schema.format === "password" ? "password" : "text" }
className={ errors.length ? "invalid" : ""}
title={ errors.length ? errors : ""}
value={value}
placeholder={description}
onChange={ this.onChange }
value={value}
placeholder={description}
onChange={ this.onChange }
disabled={isDisabled}/>)
}
}
@@ -189,8 +189,8 @@ export class JsonSchema_boolean extends Component {
return (<Select className={ errors.length ? "invalid" : ""}
title={ errors.length ? errors : ""}
value={ String(value) }
allowedValues={ fromJS(["true", "false"]) }
allowEmptyValue={ true }
allowedValues={ fromJS(schema.enum || ["true", "false"]) }
allowEmptyValue={ !this.props.required }
onChange={ this.onEnumChange }/>)
}
}
+4 -2
View File
@@ -139,7 +139,7 @@ export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers})
}
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => {
export const authorizeRequest = ( data ) => ( { fn, getConfigs, authActions, errActions, authSelectors } ) => {
let { body, query={}, headers={}, name, url, auth } = data
let { additionalQueryStringParams } = authSelectors.getConfigs() || {}
let fetchUrl = url
@@ -158,7 +158,9 @@ export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, aut
method: "post",
headers: _headers,
query: query,
body: body
body: body,
requestInterceptor: getConfigs().requestInterceptor,
responseInterceptor: getConfigs().responseInterceptor
})
.then(function (response) {
let token = JSON.parse(response.data)
+4 -4
View File
@@ -7,10 +7,10 @@ export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type"
export const UPDATE_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type"
export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value"
export function setSelectedServer (selectedServerUrl) {
export function setSelectedServer (selectedServerUrl, namespace) {
return {
type: UPDATE_SELECTED_SERVER,
payload: selectedServerUrl
payload: {selectedServerUrl, namespace}
}
}
@@ -35,9 +35,9 @@ export function setResponseContentType ({ value, path, method }) {
}
}
export function setServerVariableValue ({ server, key, val }) {
export function setServerVariableValue ({ server, namespace, key, val }) {
return {
type: UPDATE_SERVER_VARIABLE_VALUE,
payload: { server, key, val }
payload: { server, namespace, key, val }
}
}
@@ -4,6 +4,7 @@ import OperationLink from "./operation-link.jsx"
import Servers from "./servers"
import RequestBodyEditor from "./request-body-editor"
import HttpAuth from "./http-auth"
import OperationServers from "./operation-servers"
export default {
Callbacks,
@@ -11,5 +12,6 @@ export default {
RequestBody,
Servers,
RequestBodyEditor,
OperationServers,
operationLink: OperationLink
}
@@ -0,0 +1,102 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class OperationServers extends React.Component {
static propTypes = {
// for self
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
operationServers: ImPropTypes.list,
pathServers: ImPropTypes.list,
setSelectedServer: PropTypes.func.isRequired,
setServerVariableValue: PropTypes.func.isRequired,
getSelectedServer: PropTypes.func.isRequired,
getServerVariable: PropTypes.func.isRequired,
getEffectiveServerValue: PropTypes.func.isRequired,
// utils
getComponent: PropTypes.func.isRequired
}
setSelectedServer = (server) => {
const { path, method } = this.props
// FIXME: we should be keeping up with this in props/state upstream of us
// instead of cheating™ with `forceUpdate`
this.forceUpdate()
return this.props.setSelectedServer(server, `${path}:${method}`)
}
setServerVariableValue = (obj) => {
const { path, method } = this.props
// FIXME: we should be keeping up with this in props/state upstream of us
// instead of cheating™ with `forceUpdate`
this.forceUpdate()
return this.props.setServerVariableValue({
...obj,
namespace: `${path}:${method}`
})
}
getSelectedServer = () => {
const { path, method } = this.props
return this.props.getSelectedServer(`${path}:${method}`)
}
getServerVariable = (server, key) => {
const { path, method } = this.props
return this.props.getServerVariable({
namespace: `${path}:${method}`,
server
}, key)
}
getEffectiveServerValue = (server) => {
const { path, method } = this.props
return this.props.getEffectiveServerValue({
server,
namespace: `${path}:${method}`
})
}
render() {
const {
// for self
operationServers,
pathServers,
// util
getComponent
} = this.props
if(!operationServers && !pathServers) {
return null
}
const Servers = getComponent("Servers")
const serversToDisplay = operationServers || pathServers
const displaying = operationServers ? "operation" : "path"
return <div className="opblock-section operation-servers">
<div className="opblock-section-header">
<div className="tab-header">
<h4 className="opblock-title">Servers</h4>
</div>
</div>
<div className="opblock-description-wrapper">
<h4 className="message">
These {displaying}-level options override the global server options.
</h4>
<Servers
servers={serversToDisplay}
currentServer={this.getSelectedServer()}
setSelectedServer={this.setSelectedServer}
setServerVariableValue={this.setServerVariableValue}
getServerVariable={this.getServerVariable}
getEffectiveServerValue={this.getEffectiveServerValue}
/>
</div>
</div>
}
}
+8 -4
View File
@@ -15,7 +15,11 @@ export default class Servers extends React.Component {
}
componentDidMount() {
let { servers } = this.props
let { servers, currentServer } = this.props
if(currentServer) {
return
}
//fire 'change' event to set default 'value' of select
this.setServer(servers.first().get("url"))
@@ -93,9 +97,8 @@ export default class Servers extends React.Component {
let shouldShowVariableUI = currentServerVariableDefs.size !== 0
return (
<div>
<div className="servers">
<label htmlFor="servers">
<span className="servers-title">Servers</span>
<select onChange={ this.onServerChange }>
{ servers.valueSeq().map(
( server ) =>
@@ -109,13 +112,14 @@ export default class Servers extends React.Component {
</label>
{ shouldShowVariableUI ?
<div>
<h4>Server variables</h4>
<div className={"computed-url"}>
Computed URL:
<code>
{getEffectiveServerValue(currentServer)}
</code>
</div>
<h4>Server variables</h4>
<table>
<tbody>
{
+6 -4
View File
@@ -7,8 +7,9 @@ import {
} from "./actions"
export default {
[UPDATE_SELECTED_SERVER]: (state, { payload: selectedServerUrl } ) =>{
return state.setIn( [ "selectedServer" ], selectedServerUrl)
[UPDATE_SELECTED_SERVER]: (state, { payload: { selectedServerUrl, namespace } } ) =>{
const path = namespace ? [ namespace, "selectedServer"] : [ "selectedServer"]
return state.setIn( path, selectedServerUrl)
},
[UPDATE_REQUEST_BODY_VALUE]: (state, { payload: { value, pathMethod } } ) =>{
let [path, method] = pathMethod
@@ -21,7 +22,8 @@ export default {
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, path, method } } ) =>{
return state.setIn( [ "requestData", path, method, "responseContentType" ], value)
},
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{
return state.setIn( [ "serverVariableValues", server, key ], val)
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, namespace, key, val } } ) =>{
const path = namespace ? [ namespace, "serverVariableValues", server, key ] : [ "serverVariableValues", server, key ]
return state.setIn(path, val)
},
}
+59 -9
View File
@@ -15,8 +15,9 @@ function onlyOAS3(selector) {
}
}
export const selectedServer = onlyOAS3(state => {
return state.getIn(["selectedServer"]) || ""
export const selectedServer = onlyOAS3((state, namespace) => {
const path = namespace ? [namespace, "selectedServer"] : ["selectedServer"]
return state.getIn(path) || ""
}
)
@@ -35,19 +36,68 @@ export const responseContentType = onlyOAS3((state, path, method) => {
}
)
export const serverVariableValue = onlyOAS3((state, server, key) => {
return state.getIn(["serverVariableValues", server, key]) || null
export const serverVariableValue = onlyOAS3((state, locationData, key) => {
let path
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
if(namespace) {
path = [namespace, "serverVariableValues", server, key]
} else {
path = ["serverVariableValues", server, key]
}
} else {
const server = locationData
path = ["serverVariableValues", server, key]
}
return state.getIn(path) || null
}
)
export const serverVariables = onlyOAS3((state, server) => {
return state.getIn(["serverVariableValues", server]) || OrderedMap()
export const serverVariables = onlyOAS3((state, locationData) => {
let path
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
if(namespace) {
path = [namespace, "serverVariableValues", server]
} else {
path = ["serverVariableValues", server]
}
} else {
const server = locationData
path = ["serverVariableValues", server]
}
return state.getIn(path) || OrderedMap()
}
)
export const serverEffectiveValue = onlyOAS3((state, server) => {
let varValues = state.getIn(["serverVariableValues", server]) || OrderedMap()
let str = server
export const serverEffectiveValue = onlyOAS3((state, locationData) => {
var varValues, serverValue
// locationData may take one of two forms, for backwards compatibility
// Object: ({server, namespace?}) or String:(server)
if(typeof locationData !== "string") {
const { server, namespace } = locationData
serverValue = server
if(namespace) {
varValues = state.getIn([namespace, "serverVariableValues", serverValue])
} else {
varValues = state.getIn(["serverVariableValues", serverValue])
}
} else {
serverValue = locationData
varValues = state.getIn(["serverVariableValues", serverValue])
}
varValues = varValues || OrderedMap()
let str = serverValue
varValues.map((val, key) => {
str = str.replace(new RegExp(`{${key}}`, "g"), val)
@@ -8,12 +8,13 @@ class ModelComponent extends Component {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
expandDepth: PropTypes.number
}
render(){
let { schema } = this.props
let { getConfigs, schema } = this.props
let classes = ["model-box"]
let isDeprecated = schema.get("deprecated") === true
let message = null
@@ -26,6 +27,7 @@ class ModelComponent extends Component {
return <div className={classes.join(" ")}>
{message}
<Model { ...this.props }
getConfigs={ getConfigs }
depth={ 1 }
expandDepth={ this.props.expandDepth || 0 }
/>
+12 -3
View File
@@ -228,9 +228,18 @@ export const executeRequest = (req) =>
}
if(specSelectors.isOAS3()) {
// OAS3 request feature support
req.server = oas3Selectors.selectedServer()
req.serverVariables = oas3Selectors.serverVariables(req.server).toJS()
const namespace = `${pathName}:${method}`
req.server = oas3Selectors.selectedServer(namespace) || oas3Selectors.selectedServer()
const namespaceVariables = oas3Selectors.serverVariables({
server: req.server,
namespace
}).toJS()
const globalVariables = oas3Selectors.serverVariables({ server: req.server }).toJS()
req.serverVariables = Object.keys(namespaceVariables).length ? namespaceVariables : globalVariables
req.requestContentType = oas3Selectors.requestContentType(pathName, method)
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
const requestBody = oas3Selectors.requestBodyValue(pathName, method)
+6
View File
@@ -30,11 +30,14 @@ import LiveResponse from "core/components/live-response"
import OnlineValidatorBadge from "core/components/online-validator-badge"
import Operations from "core/components/operations"
import Operation from "core/components/operation"
import OperationExt from "core/components/operation-extensions"
import OperationExtRow from "core/components/operation-extension-row"
import HighlightCode from "core/components/highlight-code"
import Responses from "core/components/responses"
import Response from "core/components/response"
import ResponseBody from "core/components/response-body"
import Parameters from "core/components/parameters"
import ParameterExt from "core/components/parameter-extension"
import ParameterRow from "core/components/parameter-row"
import Execute from "core/components/execute"
import Headers from "core/components/headers"
@@ -115,6 +118,9 @@ export default function() {
Markdown,
BaseLayout,
VersionStamp,
OperationExt,
OperationExtRow,
ParameterExt,
OperationContainer
}
}
+7 -2
View File
@@ -473,6 +473,9 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
let required = param.get("required")
let paramDetails = isOAS3 ? param.get("schema") : param
if(!paramDetails) return errors
let maximum = paramDetails.get("maximum")
let minimum = paramDetails.get("minimum")
let type = paramDetails.get("type")
@@ -480,7 +483,7 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
let maxLength = paramDetails.get("maxLength")
let minLength = paramDetails.get("minLength")
let pattern = paramDetails.get("pattern")
/*
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
@@ -506,7 +509,7 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
let err = validatePattern(value, pattern)
if (err) errors.push(err)
}
if (maxLength || maxLength === 0) {
let err = validateMaxLength(value, maxLength)
if (err) errors.push(err)
@@ -692,3 +695,5 @@ export function getAcceptControllingResponse(responses) {
export const createDeepLinkPath = (str) => typeof str == "string" || str instanceof String ? str.trim().replace(/\s/g, "_") : ""
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )
export const getExtensions = (defObj) => defObj.filter((v, k) => /^x-/.test(k))
+5
View File
@@ -3,3 +3,8 @@
if(!window.Promise) {
require("core-js/fn/promise")
}
// Required by IE 11
if(!String.prototype.startsWith) {
require("core-js/es6/string")
}
+4
View File
@@ -5,6 +5,10 @@
padding: 10px 0;
justify-content: center;
.btn-done {
margin-right: 1em;
}
}
.auth-wrapper
-72
View File
@@ -650,78 +650,6 @@
}
}
.server-container
{
margin: 0 0 20px 0;
padding: 30px 0;
background: $server-container-background-color;
box-shadow: 0 1px 2px 0 rgba($server-container-box-shadow-color,.15);
.computed-url {
margin: 2em 0;
code {
color: $server-container-computed-url-code-font-color;
display: inline-block;
padding: 4px;
font-size: 16px;
margin: 0 1em;
font-style: italic;
}
}
.servers
{
display: flex;
align-items: center;
.servers-title {
margin-right: 1em;
}
> label
{
font-size: 12px;
display: flex;
flex-direction: column;
margin: -20px 15px 0 0;
@include text_headline();
select
{
min-width: 130px;
}
}
table {
tr {
width: 30em;
}
td {
display: inline-block;
max-width: 15em;
vertical-align: middle;
padding-top: 10px;
padding-bottom: 10px;
&:first-of-type {
padding-right: 2em;
}
input {
width: 100%;
height: 100%;
}
}
}
}
}
.loading-container
{
padding: 40px 0 60px;
+74
View File
@@ -0,0 +1,74 @@
.servers
{
> label
{
font-size: 12px;
margin: -20px 15px 0 0;
@include text_headline();
select
{
min-width: 130px;
}
}
h4.message {
padding-bottom: 2em;
}
table {
tr {
width: 30em;
}
td {
display: inline-block;
max-width: 15em;
vertical-align: middle;
padding-top: 10px;
padding-bottom: 10px;
&:first-of-type {
padding-right: 2em;
}
input {
width: 100%;
height: 100%;
}
}
}
.computed-url {
margin: 2em 0;
code {
display: inline-block;
padding: 4px;
font-size: 16px;
margin: 0 1em;
}
}
}
.global-server-container
{
margin: 0 0 20px 0;
padding: 30px 0;
background: $server-container-background-color;
box-shadow: 0 1px 2px 0 rgba($server-container-box-shadow-color,.15);
.servers-title {
line-height: 2em;
font-weight: bold;
}
}
.operation-servers {
h4.message {
margin-bottom: 2em;
}
}
+3 -2
View File
@@ -19,7 +19,7 @@ table
&:first-of-type
{
width: 124px;
width: 174px;
padding: 0 0 0 2em;
}
}
@@ -131,7 +131,8 @@ table
}
}
.parameter__in
.parameter__in,
.parameter__extension
{
font-size: 12px;
font-style: italic;
+1
View File
@@ -9,6 +9,7 @@
@import 'form';
@import 'modal';
@import 'models';
@import 'servers';
@import 'table';
@import 'topbar';
@import 'information';
+154
View File
@@ -0,0 +1,154 @@
/* eslint-env mocha */
import React from "react"
import expect, { createSpy } from "expect"
import { Select, Input } from "components/layout-utils"
import { render } from "enzyme"
import * as JsonSchemaComponents from "core/json-schema-components"
import { JsonSchemaForm } from "core/json-schema-components"
const components = {...JsonSchemaComponents, Select, Input}
const getComponentStub = (name) => {
if(components[name]) return components[name]
return null
}
describe("<JsonSchemaForm/>", function(){
describe("strings", function() {
it("should render the correct options for a string enum parameter", function(){
let props = {
getComponent: getComponentStub,
value: "",
onChange: () => {},
keyName: "",
fn: {},
schema: {
type: "string",
enum: ["one", "two"]
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("select").length).toEqual(1)
expect(wrapper.find("select option").length).toEqual(3)
expect(wrapper.find("select option").eq(0).text()).toEqual("--")
expect(wrapper.find("select option").eq(1).text()).toEqual("one")
expect(wrapper.find("select option").eq(2).text()).toEqual("two")
})
it("should render the correct options for a required string enum parameter", function(){
let props = {
getComponent: getComponentStub,
value: "",
onChange: () => {},
keyName: "",
fn: {},
required: true,
schema: {
type: "string",
enum: ["one", "two"]
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("select").length).toEqual(1)
expect(wrapper.find("select option").length).toEqual(2)
expect(wrapper.find("select option").eq(0).text()).toEqual("one")
expect(wrapper.find("select option").eq(1).text()).toEqual("two")
})
})
describe("booleans", function() {
it("should render the correct options for a boolean parameter", function(){
let props = {
getComponent: getComponentStub,
value: "",
onChange: () => {},
keyName: "",
fn: {},
schema: {
type: "boolean"
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("select").length).toEqual(1)
expect(wrapper.find("select option").length).toEqual(3)
expect(wrapper.find("select option").eq(0).text()).toEqual("--")
expect(wrapper.find("select option").eq(1).text()).toEqual("true")
expect(wrapper.find("select option").eq(2).text()).toEqual("false")
})
it("should render the correct options for a required enum boolean parameter", function(){
let props = {
getComponent: getComponentStub,
value: "",
onChange: () => {},
keyName: "",
fn: {},
required: true,
schema: {
type: "boolean",
enum: ["true"]
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("select").length).toEqual(1)
expect(wrapper.find("select option").length).toEqual(1)
expect(wrapper.find("select option").first().text()).toEqual("true")
})
})
describe("unknown types", function() {
it("should render unknown types as strings", function(){
let props = {
getComponent: getComponentStub,
value: "yo",
onChange: () => {},
keyName: "",
fn: {},
schema: {
type: "NotARealType"
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("input").length).toEqual(1)
// expect(wrapper.find("select input").length).toEqual(1)
// expect(wrapper.find("select option").first().text()).toEqual("true")
})
it("should render unknown types as strings when a format is passed", function(){
let props = {
getComponent: getComponentStub,
value: "yo",
onChange: () => {},
keyName: "",
fn: {},
schema: {
type: "NotARealType",
format: "NotARealFormat"
}
}
let wrapper = render(<JsonSchemaForm {...props}/>)
expect(wrapper.find("input").length).toEqual(1)
// expect(wrapper.find("select input").length).toEqual(1)
// expect(wrapper.find("select option").first().text()).toEqual("true")
})
})
})
+5
View File
@@ -19,6 +19,11 @@ describe("<ObjectModel />", function() {
}
const props = {
getComponent: c => components[c],
getConfigs: () => {
return {
showExtensions: true
}
},
isRef : false,
schema: Immutable.fromJS(
{
+4 -1
View File
@@ -14,6 +14,9 @@ describe("<PrimitiveModel/>", function() {
}
const props = {
getComponent: c => components[c],
getConfigs: () => ({
showExtensions: false
}),
name: "Name from props",
depth: 1,
schema: fromJS({
@@ -46,4 +49,4 @@ describe("<PrimitiveModel/>", function() {
})
})
} )
} )
+359
View File
@@ -0,0 +1,359 @@
import expect from "expect"
import { fromJS, OrderedMap } from "immutable"
import {
selectedServer,
serverVariableValue,
serverVariables,
serverEffectiveValue
} from "corePlugins/oas3/selectors"
import reducers from "corePlugins/oas3/reducers"
import {
setSelectedServer,
setServerVariableValue,
} from "corePlugins/oas3/actions"
describe("OAS3 plugin - state", function() {
describe("action + reducer + selector integration", function() {
describe("selectedServer", function() {
it("should set and get a global selectedServer", function() {
const state = new OrderedMap()
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setSelectedServer("http://google.com")
// Collect the new state
const newState = reducers["oas3_set_servers"](state, action)
// Get the value with the selector
const res = selectedServer(newState)(system)
expect(res).toEqual("http://google.com")
})
it("should set and get a namespaced selectedServer", function() {
const state = fromJS({
selectedServer: "http://yahoo.com"
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setSelectedServer("http://google.com", "myOperation")
// Collect the new state
const newState = reducers["oas3_set_servers"](state, action)
// Get the value with the selector
const res = selectedServer(newState, "myOperation")(system)
// Get the global selected server
const globalRes = selectedServer(newState)(system)
expect(res).toEqual("http://google.com")
expect(globalRes).toEqual("http://yahoo.com")
})
})
describe("serverVariableValue", function() {
it("should set and get a global serverVariableValue", function() {
const state = new OrderedMap()
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setServerVariableValue({
server: "google.com",
key: "foo",
val: "bar"
})
// Collect the new state
const newState = reducers["oas3_set_server_variable_value"](state, action)
// Get the value with the selector
const res = serverVariableValue(newState, "google.com", "foo")(system)
expect(res).toEqual("bar")
})
it("should set and get a namespaced serverVariableValue", function() {
const state = fromJS({
serverVariableValues: {
"google.com": {
foo: "123"
}
}
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setServerVariableValue({
namespace: "myOperation",
server: "google.com",
key: "foo",
val: "bar"
})
// Collect the new state
const newState = reducers["oas3_set_server_variable_value"](state, action)
// Get the value with the selector
const res = serverVariableValue(newState, {
namespace: "myOperation",
server: "google.com"
}, "foo")(system)
// Get the global value, to cross-check
const globalRes = serverVariableValue(newState, {
server: "google.com"
}, "foo")(system)
expect(res).toEqual("bar")
expect(globalRes).toEqual("123")
})
})
describe("serverVariables", function() {
it("should set and get global serverVariables", function() {
const state = new OrderedMap()
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setServerVariableValue({
server: "google.com",
key: "foo",
val: "bar"
})
// Collect the new state
const newState = reducers["oas3_set_server_variable_value"](state, action)
// Get the value with the selector
const res = serverVariables(newState, "google.com", "foo")(system)
expect(res.toJS()).toEqual({
foo: "bar"
})
})
it("should set and get namespaced serverVariables", function() {
const state = fromJS({
serverVariableValues: {
"google.com": {
foo: "123"
}
}
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setServerVariableValue({
namespace: "myOperation",
server: "google.com",
key: "foo",
val: "bar"
})
// Collect the new state
const newState = reducers["oas3_set_server_variable_value"](state, action)
// Get the value with the selector
const res = serverVariables(newState, {
namespace: "myOperation",
server: "google.com"
}, "foo")(system)
// Get the global value, to cross-check
const globalRes = serverVariables(newState, {
server: "google.com"
}, "foo")(system)
expect(res.toJS()).toEqual({
foo: "bar"
})
expect(globalRes.toJS()).toEqual({
foo: "123"
})
})
})
describe("serverEffectiveValue", function() {
it("should set variable values and compute a URL for a namespaced server", function() {
const state = fromJS({
serverVariableValues: {
"google.com/{foo}": {
foo: "123"
}
}
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Create the action
const action = setServerVariableValue({
namespace: "myOperation",
server: "google.com/{foo}",
key: "foo",
val: "bar"
})
// Collect the new state
const newState = reducers["oas3_set_server_variable_value"](state, action)
// Get the value with the selector
const res = serverEffectiveValue(newState, {
namespace: "myOperation",
server: "google.com/{foo}"
})(system)
// Get the global value, to cross-check
const globalRes = serverEffectiveValue(newState, {
server: "google.com/{foo}"
})(system)
expect(res).toEqual("google.com/bar")
expect(globalRes).toEqual("google.com/123")
})
})
})
describe("selectors", function() {
describe("serverEffectiveValue", function() {
it("should compute global serverEffectiveValues", function() {
const state = fromJS({
serverVariableValues: {
"google.com/{foo}/{bar}": {
foo: "123",
bar: "456"
}
}
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Get the value with the selector
const res = serverEffectiveValue(state, "google.com/{foo}/{bar}")(system)
expect(res).toEqual("google.com/123/456")
})
it("should handle multiple variable instances", function() {
const state = fromJS({
serverVariableValues: {
"google.com/{foo}/{foo}/{bar}": {
foo: "123",
bar: "456"
}
}
})
const system = {
// needed to handle `onlyOAS3` wrapper
getSystem() {
return {
specSelectors: {
specJson: () => {
return fromJS({ openapi: "3.0.0" })
}
}
}
}
}
// Get the value with the selector
const res = serverEffectiveValue(state, "google.com/{foo}/{foo}/{bar}")(system)
expect(res).toEqual("google.com/123/123/456")
})
})
})
})
+2 -5
View File
@@ -321,14 +321,11 @@ describe("utils", function() {
}
it("should check the isOAS3 flag when validating parameters", function() {
// This should "skip" validation because there is no `schema.type` property
// This should "skip" validation because there is no `schema` property
// and we are telling `validateParam` this is an OAS3 spec
param = fromJS({
value: "",
required: true,
schema: {
notTheTypeProperty: "string"
}
required: true
})
result = validateParam( param, false, true )
expect( result ).toEqual( [] )