Merge branch 'master' into array-model-markdown-description
This commit is contained in:
6
.github/issue_template.md
vendored
6
.github/issue_template.md
vendored
@@ -14,6 +14,10 @@ or anything that violates the specifications.
|
|||||||
|
|
||||||
<!--- Provide a general summary of the issue in the title above -->
|
<!--- Provide a general summary of the issue in the title above -->
|
||||||
|
|
||||||
|
<!---
|
||||||
|
If you aren't sure what Swagger-UI version, see this guide: https://github.com/swagger-api/swagger-ui/blob/master/docs/version-detection.md
|
||||||
|
--->
|
||||||
|
|
||||||
|
|
||||||
| Q | A
|
| Q | A
|
||||||
| ------------------------------- | -------
|
| ------------------------------- | -------
|
||||||
@@ -21,7 +25,7 @@ or anything that violates the specifications.
|
|||||||
| Which Swagger/OpenAPI version? |
|
| Which Swagger/OpenAPI version? |
|
||||||
| Which Swagger-UI version? |
|
| Which Swagger-UI version? |
|
||||||
| How did you install Swagger-UI? |
|
| How did you install Swagger-UI? |
|
||||||
| Which broswer & version? |
|
| Which browser & version? |
|
||||||
| Which operating system? |
|
| Which operating system? |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
|
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
|
||||||
|
|
||||||
This repo publishes to two different NPM packages:
|
This repository publishes to two different NPM modules:
|
||||||
|
|
||||||
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is intended for use as a node module.
|
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is a traditional npm module intended for use in JavaScript web application projects that are capable of resolving dependencies (via Webpack, Browserify, etc).
|
||||||
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) comes pre-bundled with all dependencies and can be incorporated directly in a webapp.
|
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) is a dependency-free module that includes everything you need to serve Swagger-UI in a server-side project, or a web project that can't resolve npm module dependencies.
|
||||||
|
|
||||||
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||||
|
|
||||||
@@ -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
|
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||||
------------------ | ------------ | -------------------------- | -----
|
------------------ | ------------ | -------------------------- | -----
|
||||||
3.1.4 | 2017-08-05 | 2.0, 3.0 | [tag v3.1.4](https://github.com/swagger-api/swagger-ui/tree/v3.1.4)
|
3.2.2 | 2017-09-22 | 2.0, 3.0 | [tag v3.2.2](https://github.com/swagger-api/swagger-ui/tree/v3.2.2)
|
||||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
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.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)
|
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)
|
||||||
@@ -46,7 +46,7 @@ Will start nginx with swagger-ui on port 80.
|
|||||||
Or you can provide your own swagger.json on your host
|
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
|
docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Prerequisites
|
##### Prerequisites
|
||||||
@@ -151,6 +151,8 @@ domNode | The HTML DOM element inside which SwaggerUi will put the user interfac
|
|||||||
oauth2RedirectUrl | OAuth redirect URL
|
oauth2RedirectUrl | OAuth redirect URL
|
||||||
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
||||||
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||||
|
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be set to 'model' or 'example', and the default is 'example'.
|
||||||
|
defaultModelExpandDepth | The default expansion depth for models. The default value is 1.
|
||||||
configUrl | Configs URL
|
configUrl | Configs URL
|
||||||
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||||
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||||
@@ -160,6 +162,9 @@ 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.
|
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.
|
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)
|
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.
|
||||||
|
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.
|
||||||
|
|
||||||
### Plugins
|
### Plugins
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
var redirectUrl = oauth2.redirectUrl;
|
var redirectUrl = oauth2.redirectUrl;
|
||||||
var isValid, qp, arr;
|
var isValid, qp, arr;
|
||||||
|
|
||||||
qp = (window.location.hash || location.search).substring(1);
|
if (/code|token|error/.test(window.location.hash)) {
|
||||||
|
qp = window.location.hash.substring(1);
|
||||||
|
} else {
|
||||||
|
qp = location.search.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
arr = qp.split("&")
|
arr = qp.split("&")
|
||||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||||
|
|||||||
6
dist/oauth2-redirect.html
vendored
6
dist/oauth2-redirect.html
vendored
@@ -11,7 +11,11 @@
|
|||||||
var redirectUrl = oauth2.redirectUrl;
|
var redirectUrl = oauth2.redirectUrl;
|
||||||
var isValid, qp, arr;
|
var isValid, qp, arr;
|
||||||
|
|
||||||
qp = (window.location.hash || location.search).substring(1);
|
if (/code|token|error/.test(window.location.hash)) {
|
||||||
|
qp = window.location.hash.substring(1);
|
||||||
|
} else {
|
||||||
|
qp = location.search.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
arr = qp.split("&")
|
arr = qp.split("&")
|
||||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||||
|
|||||||
27
dist/swagger-ui-bundle.js
vendored
27
dist/swagger-ui-bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-bundle.js.map
vendored
2
dist/swagger-ui-bundle.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAoyKA;;;;;;AAy+EA;;;;;;;;;;;;;;;;;;;;;;;;;;AAw1TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAw6oBA;;;;;AAirQA;AAm4DA;;;;;;AAo4YA;;;;;;AA8jaA;AAumvBA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AA4kMA;;;;;;AA65DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAq9TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAo/pBA;;;;;AAk6QA;;;;;AAynBA;AAi0CA;;;;;;AAq/YA;;;;;;AAojaA;AA8lvBA","sourceRoot":""}
|
||||||
6
dist/swagger-ui-standalone-preset.js
vendored
6
dist/swagger-ui-standalone-preset.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-standalone-preset.js.map
vendored
2
dist/swagger-ui-standalone-preset.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA00CA;;;;;;AAmlFA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA80CA;;;;;;AAqpFA","sourceRoot":""}
|
||||||
2
dist/swagger-ui.css
vendored
2
dist/swagger-ui.css
vendored
File diff suppressed because one or more lines are too long
4
dist/swagger-ui.js
vendored
4
dist/swagger-ui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.js.map
vendored
2
dist/swagger-ui.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAowcA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAkzeA","sourceRoot":""}
|
||||||
BIN
docs/images/swagger-ui2.png
Normal file
BIN
docs/images/swagger-ui2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 390 KiB |
BIN
docs/images/swagger-ui3.png
Normal file
BIN
docs/images/swagger-ui3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 297 KiB |
54
docs/version-detection.md
Normal file
54
docs/version-detection.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Detecting your Swagger-UI version
|
||||||
|
|
||||||
|
At times, you're going to need to know which version of Swagger-UI you use.
|
||||||
|
|
||||||
|
The first step would be to detect which major version you currently use, as the method of detecting the version has changed. If your Swagger-UI has been heavily modified and you cannot detect from the look and feel which major version you use, you'd have to try both methods to get the exact version.
|
||||||
|
|
||||||
|
To help you visually detect which version you're using, we've included supporting images.
|
||||||
|
|
||||||
|
|
||||||
|
# Swagger-UI 3.X
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Some distinct identifiers to Swagger-UI 3.X:
|
||||||
|
- The API version appears as a badge next to its title.
|
||||||
|
- If there are schemes or authorizations, they'd appear in a bar above the operations.
|
||||||
|
- Try it out functionality is not enabled by default.
|
||||||
|
- All the response codes in the operations appear at after the parameters.
|
||||||
|
- There's a models section after the operations.
|
||||||
|
|
||||||
|
If you've determined this is the version you have, to find the exact version:
|
||||||
|
- Open your browser's web console (changes between browsers)
|
||||||
|
- Type `versions` in the console and execute the call.
|
||||||
|
- You might need to expand the result, until you get a string similar to `swaggerUi : Object { version: "3.1.6", gitRevision: "g786cd47", gitDirty: true, … }`.
|
||||||
|
- The version taken from that example would be `3.1.6`.
|
||||||
|
|
||||||
|
Note: This functionality was added in 3.0.8. If you're unable to execute it, you're likely to use an older version, and in that case the first step would be to upgrade.
|
||||||
|
|
||||||
|
|
||||||
|
# Swagger-UI 2.X and under
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Some distinct identifiers to Swagger-UI 3.X:
|
||||||
|
- The API version appears at the bottom of the page.
|
||||||
|
- Schemes are not rendered.
|
||||||
|
- Authorization, if rendered, will appear next to the navigation bar.
|
||||||
|
- Try it out functionality is enabled by default.
|
||||||
|
- The successful response code would appear above the parameters, the rest below them.
|
||||||
|
- There's no models section after the operations.
|
||||||
|
|
||||||
|
If you've determined this is the version you have, to find the exact version:
|
||||||
|
- Navigate to the sources of the UI. Either on your disk or via the view page source functionality in your browser.
|
||||||
|
- Find an open the `swagger-ui.js`
|
||||||
|
- At the top of the page, there would be a comment containing the exact version of swagger-ui. This example shows version `2.2.9`:
|
||||||
|
|
||||||
|
```
|
||||||
|
/**
|
||||||
|
* swagger-ui - Swagger UI is a dependency-free collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API
|
||||||
|
* @version v2.2.9
|
||||||
|
* @link http://swagger.io
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "swagger-ui",
|
"name": "swagger-ui",
|
||||||
"version": "3.1.4",
|
"version": "3.2.2",
|
||||||
"main": "dist/swagger-ui.js",
|
"main": "dist/swagger-ui.js",
|
||||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.2.0",
|
"base64-js": "^1.2.0",
|
||||||
"brace": "0.7.0",
|
"brace": "0.7.0",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"commonmark": "^0.28.1",
|
||||||
|
"css.escape": "1.5.1",
|
||||||
"deep-extend": "0.4.1",
|
"deep-extend": "0.4.1",
|
||||||
"expect": "1.20.2",
|
"expect": "1.20.2",
|
||||||
"getbase": "^2.8.2",
|
"getbase": "^2.8.2",
|
||||||
@@ -65,17 +68,17 @@
|
|||||||
"react-motion": "0.4.4",
|
"react-motion": "0.4.4",
|
||||||
"react-object-inspector": "0.2.1",
|
"react-object-inspector": "0.2.1",
|
||||||
"react-redux": "^4.x.x",
|
"react-redux": "^4.x.x",
|
||||||
"react-remarkable": "1.1.1",
|
|
||||||
"react-split-pane": "0.1.57",
|
"react-split-pane": "0.1.57",
|
||||||
"redux": "^3.x.x",
|
"redux": "^3.x.x",
|
||||||
"redux-immutable": "3.0.8",
|
"redux-immutable": "3.0.8",
|
||||||
"redux-logger": "*",
|
"redux-logger": "*",
|
||||||
|
"remarkable": "^1.7.1",
|
||||||
"reselect": "2.5.3",
|
"reselect": "2.5.3",
|
||||||
"sanitize-html": "^1.14.1",
|
"sanitize-html": "^1.14.1",
|
||||||
"scroll-to-element": "^2.0.0",
|
"scroll-to-element": "^2.0.0",
|
||||||
"serialize-error": "2.0.0",
|
"serialize-error": "2.0.0",
|
||||||
"shallowequal": "0.2.2",
|
"shallowequal": "0.2.2",
|
||||||
"swagger-client": "3.0.19",
|
"swagger-client": "^3.1.2",
|
||||||
"url-parse": "^1.1.8",
|
"url-parse": "^1.1.8",
|
||||||
"whatwg-fetch": "0.11.1",
|
"whatwg-fetch": "0.11.1",
|
||||||
"worker-loader": "^0.7.1",
|
"worker-loader": "^0.7.1",
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ export default class ArrayModel extends Component {
|
|||||||
<span className="model-title__text">{ title }</span>
|
<span className="model-title__text">{ title }</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note: we set `name={null}` in <Model> below because we don't want
|
||||||
|
the name of the current Model passed (and displayed) as the name of the array element Model
|
||||||
|
*/
|
||||||
|
|
||||||
return <span className="model">
|
return <span className="model">
|
||||||
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
||||||
[
|
[
|
||||||
@@ -42,7 +47,7 @@ export default class ArrayModel extends Component {
|
|||||||
!description ? null :
|
!description ? null :
|
||||||
<Markdown source={ description } />
|
<Markdown source={ description } />
|
||||||
}
|
}
|
||||||
<span><Model { ...this.props } schema={ items } required={ false } depth={ depth + 1 } /></span>
|
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
|
||||||
]
|
]
|
||||||
</ModelCollapse>
|
</ModelCollapse>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export default class BaseLayout extends React.Component {
|
|||||||
errActions: PropTypes.object.isRequired,
|
errActions: PropTypes.object.isRequired,
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
oas3Selectors: PropTypes.object.isRequired,
|
||||||
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
layoutSelectors: PropTypes.object.isRequired,
|
layoutSelectors: PropTypes.object.isRequired,
|
||||||
layoutActions: PropTypes.object.isRequired,
|
layoutActions: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired
|
getComponent: PropTypes.func.isRequired
|
||||||
@@ -19,7 +21,14 @@ export default class BaseLayout extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { specSelectors, specActions, getComponent, layoutSelectors } = this.props
|
let {
|
||||||
|
specSelectors,
|
||||||
|
specActions,
|
||||||
|
getComponent,
|
||||||
|
layoutSelectors,
|
||||||
|
oas3Selectors,
|
||||||
|
oas3Actions
|
||||||
|
} = this.props
|
||||||
|
|
||||||
let info = specSelectors.info()
|
let info = specSelectors.info()
|
||||||
let url = specSelectors.url()
|
let url = specSelectors.url()
|
||||||
@@ -28,6 +37,7 @@ export default class BaseLayout extends React.Component {
|
|||||||
let securityDefinitions = specSelectors.securityDefinitions()
|
let securityDefinitions = specSelectors.securityDefinitions()
|
||||||
let externalDocs = specSelectors.externalDocs()
|
let externalDocs = specSelectors.externalDocs()
|
||||||
let schemes = specSelectors.schemes()
|
let schemes = specSelectors.schemes()
|
||||||
|
let servers = specSelectors.servers()
|
||||||
|
|
||||||
let Info = getComponent("info")
|
let Info = getComponent("info")
|
||||||
let Operations = getComponent("operations", true)
|
let Operations = getComponent("operations", true)
|
||||||
@@ -35,6 +45,7 @@ export default class BaseLayout extends React.Component {
|
|||||||
let AuthorizeBtn = getComponent("authorizeBtn", true)
|
let AuthorizeBtn = getComponent("authorizeBtn", true)
|
||||||
let Row = getComponent("Row")
|
let Row = getComponent("Row")
|
||||||
let Col = getComponent("Col")
|
let Col = getComponent("Col")
|
||||||
|
let Servers = getComponent("Servers")
|
||||||
let Errors = getComponent("errors", true)
|
let Errors = getComponent("errors", true)
|
||||||
|
|
||||||
let isLoading = specSelectors.loadingStatus() === "loading"
|
let isLoading = specSelectors.loadingStatus() === "loading"
|
||||||
@@ -82,6 +93,22 @@ export default class BaseLayout extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
) : null }
|
) : null }
|
||||||
|
|
||||||
|
{ servers && servers.size ? (
|
||||||
|
<div className="server-container">
|
||||||
|
<Col className="servers wrapper" mobile={12}>
|
||||||
|
<Servers
|
||||||
|
servers={servers}
|
||||||
|
currentServer={oas3Selectors.selectedServer()}
|
||||||
|
setSelectedServer={oas3Actions.setSelectedServer}
|
||||||
|
setServerVariableValue={oas3Actions.setServerVariableValue}
|
||||||
|
getServerVariable={oas3Selectors.serverVariableValue}
|
||||||
|
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
) : null}
|
||||||
|
|
||||||
{
|
{
|
||||||
filter === null || filter === false ? null :
|
filter === null || filter === false ? null :
|
||||||
<div className="filter-container">
|
<div className="filter-container">
|
||||||
|
|||||||
@@ -29,13 +29,18 @@ Duration.propTypes = {
|
|||||||
export default class LiveResponse extends React.Component {
|
export default class LiveResponse extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
response: PropTypes.object.isRequired,
|
response: PropTypes.object.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
pathMethod: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
displayRequestDuration: PropTypes.bool.isRequired
|
displayRequestDuration: PropTypes.bool.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { request, response, getComponent, displayRequestDuration } = this.props
|
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, pathMethod } = this.props
|
||||||
|
const { showMutatedRequest } = getConfigs()
|
||||||
|
|
||||||
|
const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(pathMethod[0], pathMethod[1]) : specSelectors.requestFor(pathMethod[0], pathMethod[1])
|
||||||
const status = response.get("status")
|
const status = response.get("status")
|
||||||
const url = response.get("url")
|
const url = response.get("url")
|
||||||
const headers = response.get("headers").toJS()
|
const headers = response.get("headers").toJS()
|
||||||
@@ -55,7 +60,7 @@ export default class LiveResponse extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ request && <Curl request={ request }/> }
|
{ curlRequest && <Curl request={ curlRequest }/> }
|
||||||
<h4>Server response</h4>
|
<h4>Server response</h4>
|
||||||
<table className="responses-table">
|
<table className="responses-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -7,14 +7,19 @@ export default class ModelExample extends React.Component {
|
|||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
schema: PropTypes.object.isRequired,
|
schema: PropTypes.object.isRequired,
|
||||||
example: PropTypes.any.isRequired,
|
example: PropTypes.any.isRequired,
|
||||||
isExecute: PropTypes.bool
|
isExecute: PropTypes.bool,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context)
|
super(props, context)
|
||||||
|
let { getConfigs } = this.props
|
||||||
|
let { defaultModelRendering } = getConfigs()
|
||||||
|
if (defaultModelRendering !== "example" && defaultModelRendering !== "model") {
|
||||||
|
defaultModelRendering = "example"
|
||||||
|
}
|
||||||
this.state = {
|
this.state = {
|
||||||
activeTab: "example"
|
activeTab: defaultModelRendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +32,8 @@ export default class ModelExample extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { getComponent, specSelectors, schema, example, isExecute } = this.props
|
let { getComponent, specSelectors, schema, example, isExecute, getConfigs } = this.props
|
||||||
|
let { defaultModelExpandDepth } = getConfigs()
|
||||||
const ModelWrapper = getComponent("ModelWrapper")
|
const ModelWrapper = getComponent("ModelWrapper")
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
@@ -47,7 +53,7 @@ export default class ModelExample extends React.Component {
|
|||||||
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
|
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
expandDepth={ 1 } />
|
expandDepth={ defaultModelExpandDepth } />
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,39 +30,38 @@ export default class Model extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { getComponent, specSelectors, schema, required, name, isRef } = this.props
|
let { getComponent, specSelectors, schema, required, name, isRef } = this.props
|
||||||
let ObjectModel = getComponent("ObjectModel")
|
const ObjectModel = getComponent("ObjectModel")
|
||||||
let ArrayModel = getComponent("ArrayModel")
|
const ArrayModel = getComponent("ArrayModel")
|
||||||
let PrimitiveModel = getComponent("PrimitiveModel")
|
const PrimitiveModel = getComponent("PrimitiveModel")
|
||||||
|
let type = "object"
|
||||||
let $$ref = schema && schema.get("$$ref")
|
let $$ref = schema && schema.get("$$ref")
|
||||||
let modelName = $$ref && this.getModelName( $$ref )
|
|
||||||
let modelSchema, type
|
// If we weren't passed a `name` but have a ref, grab the name from the ref
|
||||||
|
if ( !name && $$ref ) {
|
||||||
|
name = this.getModelName( $$ref )
|
||||||
|
}
|
||||||
|
// If we weren't passed a `schema` but have a ref, grab the schema from the ref
|
||||||
|
if ( !schema && $$ref ) {
|
||||||
|
schema = this.getRefSchema( name )
|
||||||
|
}
|
||||||
|
|
||||||
const deprecated = specSelectors.isOAS3() && schema.get("deprecated")
|
const deprecated = specSelectors.isOAS3() && schema.get("deprecated")
|
||||||
|
isRef = isRef !== undefined ? isRef : !!$$ref
|
||||||
if ( schema && (schema.get("type") || schema.get("properties")) ) {
|
type = schema && schema.get("type") || type
|
||||||
modelSchema = schema
|
|
||||||
} else if ( $$ref ) {
|
|
||||||
modelSchema = this.getRefSchema( modelName )
|
|
||||||
}
|
|
||||||
|
|
||||||
type = modelSchema && modelSchema.get("type")
|
|
||||||
if ( !type && modelSchema && modelSchema.get("properties") ) {
|
|
||||||
type = "object"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case "object":
|
case "object":
|
||||||
return <ObjectModel
|
return <ObjectModel
|
||||||
className="object" { ...this.props }
|
className="object" { ...this.props }
|
||||||
schema={ modelSchema }
|
schema={ schema }
|
||||||
name={ modelName || name }
|
name={ name }
|
||||||
deprecated={deprecated}
|
deprecated={deprecated}
|
||||||
isRef={ isRef!== undefined ? isRef : !!$$ref } />
|
isRef={ isRef } />
|
||||||
case "array":
|
case "array":
|
||||||
return <ArrayModel
|
return <ArrayModel
|
||||||
className="array" { ...this.props }
|
className="array" { ...this.props }
|
||||||
schema={ modelSchema }
|
schema={ schema }
|
||||||
name={ modelName || name }
|
name={ name }
|
||||||
deprecated={deprecated}
|
deprecated={deprecated}
|
||||||
required={ required } />
|
required={ required } />
|
||||||
case "string":
|
case "string":
|
||||||
@@ -73,9 +72,10 @@ export default class Model extends Component {
|
|||||||
return <PrimitiveModel
|
return <PrimitiveModel
|
||||||
{ ...this.props }
|
{ ...this.props }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
schema={ modelSchema }
|
schema={ schema }
|
||||||
name={ modelName || name }
|
name={ name }
|
||||||
deprecated={deprecated}
|
deprecated={deprecated}
|
||||||
required={ required }/> }
|
required={ required }/>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default class Models extends Component {
|
|||||||
render(){
|
render(){
|
||||||
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
||||||
let definitions = specSelectors.definitions()
|
let definitions = specSelectors.definitions()
|
||||||
let { docExpansion } = getConfigs()
|
let { docExpansion, defaultModelExpandDepth } = getConfigs()
|
||||||
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
||||||
|
|
||||||
const ModelWrapper = getComponent("ModelWrapper")
|
const ModelWrapper = getComponent("ModelWrapper")
|
||||||
@@ -33,8 +33,8 @@ export default class Models extends Component {
|
|||||||
definitions.entrySeq().map( ( [ name, model ])=>{
|
definitions.entrySeq().map( ( [ name, model ])=>{
|
||||||
return <div className="model-container" key={ `models-section-${name}` }>
|
return <div className="model-container" key={ `models-section-${name}` }>
|
||||||
<ModelWrapper name={ name }
|
<ModelWrapper name={ name }
|
||||||
|
expandDepth={ defaultModelExpandDepth }
|
||||||
schema={ model }
|
schema={ model }
|
||||||
isRef={ true }
|
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
specSelectors={ specSelectors }/>
|
specSelectors={ specSelectors }/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export default class Operation extends PureComponent {
|
|||||||
authSelectors: PropTypes.object,
|
authSelectors: PropTypes.object,
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
layoutActions: PropTypes.object.isRequired,
|
layoutActions: PropTypes.object.isRequired,
|
||||||
layoutSelectors: PropTypes.object.isRequired,
|
layoutSelectors: PropTypes.object.isRequired,
|
||||||
fn: PropTypes.object.isRequired,
|
fn: PropTypes.object.isRequired,
|
||||||
@@ -117,7 +118,8 @@ export default class Operation extends PureComponent {
|
|||||||
specSelectors,
|
specSelectors,
|
||||||
authActions,
|
authActions,
|
||||||
authSelectors,
|
authSelectors,
|
||||||
getConfigs
|
getConfigs,
|
||||||
|
oas3Actions
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
let summary = operation.get("summary")
|
let summary = operation.get("summary")
|
||||||
@@ -147,7 +149,7 @@ export default class Operation extends PureComponent {
|
|||||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||||
|
|
||||||
// Merge in Live Response
|
// Merge in Live Response
|
||||||
if(response && response.size > 0) {
|
if(responses && response && response.size > 0) {
|
||||||
let notDocumented = !responses.get(String(response.get("status")))
|
let notDocumented = !responses.get(String(response.get("status")))
|
||||||
response = response.set("notDocumented", notDocumented)
|
response = response.set("notDocumented", notDocumented)
|
||||||
}
|
}
|
||||||
@@ -163,8 +165,8 @@ export default class Operation extends PureComponent {
|
|||||||
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
|
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
|
||||||
<a
|
<a
|
||||||
className="nostyle"
|
className="nostyle"
|
||||||
onClick={(e) => e.preventDefault()}
|
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null}
|
||||||
href={ isDeepLinkingEnabled ? `#/${isShownKey[1]}/${isShownKey[2]}` : ""} >
|
href={isDeepLinkingEnabled ? `#/${isShownKey[1]}/${isShownKey[2]}` : null}>
|
||||||
<span>{path}</span>
|
<span>{path}</span>
|
||||||
</a>
|
</a>
|
||||||
<JumpToPath path={jumpToKey} />
|
<JumpToPath path={jumpToKey} />
|
||||||
@@ -222,6 +224,7 @@ export default class Operation extends PureComponent {
|
|||||||
specActions={ specActions }
|
specActions={ specActions }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
pathMethod={ [path, method] }
|
pathMethod={ [path, method] }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
|
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
|
||||||
@@ -263,7 +266,9 @@ export default class Operation extends PureComponent {
|
|||||||
request={ request }
|
request={ request }
|
||||||
tryItOutResponse={ response }
|
tryItOutResponse={ response }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
|
oas3Actions={oas3Actions}
|
||||||
specActions={ specActions }
|
specActions={ specActions }
|
||||||
produces={ produces }
|
produces={ produces }
|
||||||
producesValue={ operation.get("produces_value") }
|
producesValue={ operation.get("produces_value") }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { helpers } from "swagger-client"
|
import { helpers } from "swagger-client"
|
||||||
|
import { createDeepLinkPath } from "core/utils"
|
||||||
const { opId } = helpers
|
const { opId } = helpers
|
||||||
|
|
||||||
export default class Operations extends React.Component {
|
export default class Operations extends React.Component {
|
||||||
@@ -9,6 +9,7 @@ export default class Operations extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
layoutSelectors: PropTypes.object.isRequired,
|
layoutSelectors: PropTypes.object.isRequired,
|
||||||
layoutActions: PropTypes.object.isRequired,
|
layoutActions: PropTypes.object.isRequired,
|
||||||
@@ -21,6 +22,7 @@ export default class Operations extends React.Component {
|
|||||||
let {
|
let {
|
||||||
specSelectors,
|
specSelectors,
|
||||||
specActions,
|
specActions,
|
||||||
|
oas3Actions,
|
||||||
getComponent,
|
getComponent,
|
||||||
layoutSelectors,
|
layoutSelectors,
|
||||||
layoutActions,
|
layoutActions,
|
||||||
@@ -34,6 +36,7 @@ export default class Operations extends React.Component {
|
|||||||
|
|
||||||
const Operation = getComponent("operation")
|
const Operation = getComponent("operation")
|
||||||
const Collapse = getComponent("Collapse")
|
const Collapse = getComponent("Collapse")
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
|
|
||||||
let showSummary = layoutSelectors.showSummary()
|
let showSummary = layoutSelectors.showSummary()
|
||||||
let {
|
let {
|
||||||
@@ -69,7 +72,7 @@ export default class Operations extends React.Component {
|
|||||||
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
||||||
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
||||||
|
|
||||||
let isShownKey = ["operations-tag", tag]
|
let isShownKey = ["operations-tag", createDeepLinkPath(tag)]
|
||||||
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -81,13 +84,13 @@ export default class Operations extends React.Component {
|
|||||||
id={isShownKey.join("-")}>
|
id={isShownKey.join("-")}>
|
||||||
<a
|
<a
|
||||||
className="nostyle"
|
className="nostyle"
|
||||||
onClick={(e) => e.preventDefault()}
|
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null}
|
||||||
href={ isDeepLinkingEnabled ? `#/${tag}` : ""}>
|
href= {isDeepLinkingEnabled ? `#/${tag}` : null}>
|
||||||
<span>{tag}</span>
|
<span>{tag}</span>
|
||||||
</a>
|
</a>
|
||||||
{ !tagDescription ? null :
|
{ !tagDescription ? null :
|
||||||
<small>
|
<small>
|
||||||
{ tagDescription }
|
<Markdown source={tagDescription} />
|
||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +127,7 @@ export default class Operations extends React.Component {
|
|||||||
|
|
||||||
const operationId =
|
const operationId =
|
||||||
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
|
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
|
||||||
const isShownKey = ["operations", tag, operationId]
|
const isShownKey = ["operations", createDeepLinkPath(tag), createDeepLinkPath(operationId)]
|
||||||
|
|
||||||
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
|
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
|
||||||
const response = specSelectors.responseFor(op.get("path"), op.get("method"))
|
const response = specSelectors.responseFor(op.get("path"), op.get("method"))
|
||||||
@@ -147,6 +150,8 @@ export default class Operations extends React.Component {
|
|||||||
specActions={ specActions }
|
specActions={ specActions }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
|
|
||||||
|
oas3Actions={oas3Actions}
|
||||||
|
|
||||||
layoutActions={ layoutActions }
|
layoutActions={ layoutActions }
|
||||||
layoutSelectors={ layoutSelectors }
|
layoutSelectors={ layoutSelectors }
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
|
|||||||
|
|
||||||
updateValues = (props) => {
|
updateValues = (props) => {
|
||||||
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
|
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
|
||||||
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : {}
|
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : {}
|
||||||
let isXml = /xml/i.test(consumesValue)
|
let isXml = /xml/i.test(consumesValue)
|
||||||
let isJson = /json/i.test(consumesValue)
|
let isJson = /json/i.test(consumesValue)
|
||||||
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
||||||
@@ -107,7 +107,7 @@ export default class ParamBody extends PureComponent {
|
|||||||
const HighlightCode = getComponent("highlightCode")
|
const HighlightCode = getComponent("highlightCode")
|
||||||
const ContentType = getComponent("contentType")
|
const ContentType = getComponent("contentType")
|
||||||
// for domains where specSelectors not passed
|
// for domains where specSelectors not passed
|
||||||
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : param
|
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : param
|
||||||
let errors = parameter.get("errors", List())
|
let errors = parameter.get("errors", List())
|
||||||
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
|
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
|
||||||
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
|
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ export default class ParameterRow extends Component {
|
|||||||
isExecute: PropTypes.bool,
|
isExecute: PropTypes.bool,
|
||||||
onChangeConsumes: PropTypes.func.isRequired,
|
onChangeConsumes: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
pathMethod: PropTypes.array.isRequired
|
pathMethod: PropTypes.array.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@@ -19,7 +20,7 @@ export default class ParameterRow extends Component {
|
|||||||
|
|
||||||
let { specSelectors, pathMethod, param } = props
|
let { specSelectors, pathMethod, param } = props
|
||||||
let defaultValue = param.get("default")
|
let defaultValue = param.get("default")
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let value = parameter ? parameter.get("value") : ""
|
let value = parameter ? parameter.get("value") : ""
|
||||||
if ( defaultValue !== undefined && value === undefined ) {
|
if ( defaultValue !== undefined && value === undefined ) {
|
||||||
this.onChangeWrapper(defaultValue)
|
this.onChangeWrapper(defaultValue)
|
||||||
@@ -30,7 +31,7 @@ export default class ParameterRow extends Component {
|
|||||||
let { specSelectors, pathMethod, param } = props
|
let { specSelectors, pathMethod, param } = props
|
||||||
let example = param.get("example")
|
let example = param.get("example")
|
||||||
let defaultValue = param.get("default")
|
let defaultValue = param.get("default")
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let paramValue = parameter ? parameter.get("value") : undefined
|
let paramValue = parameter ? parameter.get("value") : undefined
|
||||||
let enumValue = parameter ? parameter.get("enum") : undefined
|
let enumValue = parameter ? parameter.get("enum") : undefined
|
||||||
let value
|
let value
|
||||||
@@ -56,7 +57,7 @@ export default class ParameterRow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
let {param, onChange, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
||||||
|
|
||||||
let { isOAS3 } = specSelectors
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
@@ -81,13 +82,12 @@ export default class ParameterRow extends Component {
|
|||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
|
|
||||||
let schema = param.get("schema")
|
let schema = param.get("schema")
|
||||||
|
|
||||||
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
|
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
|
||||||
let isFormData = inType === "formData"
|
let isFormData = inType === "formData"
|
||||||
let isFormDataSupported = "FormData" in win
|
let isFormDataSupported = "FormData" in win
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
|
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||||
let value = parameter ? parameter.get("value") : ""
|
let value = parameter ? parameter.get("value") : ""
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -121,6 +121,7 @@ export default class ParameterRow extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
bodyParam && schema ? <ModelExample getComponent={ getComponent }
|
bodyParam && schema ? <ModelExample getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
isExecute={ isExecute }
|
isExecute={ isExecute }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
schema={ schema }
|
schema={ schema }
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ export default class Parameters extends Component {
|
|||||||
onTryoutClick: PropTypes.func,
|
onTryoutClick: PropTypes.func,
|
||||||
onCancelClick: PropTypes.func,
|
onCancelClick: PropTypes.func,
|
||||||
onChangeKey: PropTypes.array,
|
onChangeKey: PropTypes.array,
|
||||||
pathMethod: PropTypes.array.isRequired
|
pathMethod: PropTypes.array.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ export default class Parameters extends Component {
|
|||||||
onChangeKey,
|
onChangeKey,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
changeParam( onChangeKey, param.get("name"), value, isXml)
|
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeConsumesWrapper = ( val ) => {
|
onChangeConsumesWrapper = ( val ) => {
|
||||||
@@ -60,6 +61,7 @@ export default class Parameters extends Component {
|
|||||||
|
|
||||||
fn,
|
fn,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
pathMethod
|
pathMethod
|
||||||
} = this.props
|
} = this.props
|
||||||
@@ -93,8 +95,9 @@ export default class Parameters extends Component {
|
|||||||
eachMap(parameters, (parameter) => (
|
eachMap(parameters, (parameter) => (
|
||||||
<ParameterRow fn={ fn }
|
<ParameterRow fn={ fn }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
param={ parameter }
|
param={ parameter }
|
||||||
key={ parameter.get( "name" ) }
|
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
|
||||||
onChange={ this.onChange }
|
onChange={ this.onChange }
|
||||||
onChangeConsumes={this.onChangeConsumesWrapper}
|
onChangeConsumes={this.onChangeConsumesWrapper}
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default class Primitive extends Component {
|
|||||||
let format = schema.get("format")
|
let format = schema.get("format")
|
||||||
let xml = schema.get("xml")
|
let xml = schema.get("xml")
|
||||||
let enumArray = schema.get("enum")
|
let enumArray = schema.get("enum")
|
||||||
|
let title = schema.get("title") || name
|
||||||
let description = schema.get("description")
|
let description = schema.get("description")
|
||||||
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
@@ -30,7 +31,7 @@ export default class Primitive extends Component {
|
|||||||
|
|
||||||
return <span className="model">
|
return <span className="model">
|
||||||
<span className="prop">
|
<span className="prop">
|
||||||
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ name }</span> }
|
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ title }</span> }
|
||||||
<span className="prop-type">{ type }</span>
|
<span className="prop-type">{ type }</span>
|
||||||
{ format && <span className="prop-format">(${format})</span>}
|
{ format && <span className="prop-format">(${format})</span>}
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import Remarkable from "react-remarkable"
|
import Remarkable from "remarkable"
|
||||||
import sanitize from "sanitize-html"
|
import sanitize from "sanitize-html"
|
||||||
|
|
||||||
function Markdown({ source }) {
|
function Markdown({ source }) {
|
||||||
const sanitized = sanitizer(source)
|
const html = new Remarkable({
|
||||||
|
html: true,
|
||||||
|
typographer: true,
|
||||||
|
breaks: true,
|
||||||
|
linkify: true,
|
||||||
|
linkTarget: "_blank"
|
||||||
|
}).render(source)
|
||||||
|
const sanitized = sanitizer(html)
|
||||||
|
|
||||||
// sometimes the sanitizer returns "undefined" as a string
|
if ( !source || !html || !sanitized ) {
|
||||||
if(!source || !sanitized || sanitized === "undefined") {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="markdown">
|
return (
|
||||||
<Remarkable
|
<div className="markdown" dangerouslySetInnerHTML={{ __html: sanitized }}></div>
|
||||||
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
|
)
|
||||||
source={sanitized}
|
|
||||||
></Remarkable>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Markdown.propTypes = {
|
Markdown.propTypes = {
|
||||||
@@ -26,9 +29,9 @@ Markdown.propTypes = {
|
|||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
||||||
const sanitizeOptions = {
|
const sanitizeOptions = {
|
||||||
|
allowedTags: sanitize.defaults.allowedTags.concat([ "img" ]),
|
||||||
textFilter: function(text) {
|
textFilter: function(text) {
|
||||||
return text
|
return text.replace(/"/g, "\"")
|
||||||
.replace(/"/g, "\"")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ export default class ResponseBody extends React.Component {
|
|||||||
// Download
|
// Download
|
||||||
} else if (
|
} else if (
|
||||||
/^application\/octet-stream/i.test(contentType) ||
|
/^application\/octet-stream/i.test(contentType) ||
|
||||||
headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"]) ||
|
(headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"])) ||
|
||||||
headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"]) ||
|
(headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"])) ||
|
||||||
headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"]) ||
|
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
|
||||||
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"]
|
let contentLength = headers["content-length"] || headers["Content-Length"]
|
||||||
if ( !(+contentLength) ) return null
|
if ( !(+contentLength) ) return null
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
|
import cx from "classnames"
|
||||||
import { fromJS, Seq } from "immutable"
|
import { fromJS, Seq } from "immutable"
|
||||||
import { getSampleSchema } from "core/utils"
|
import { getSampleSchema, fromJSOrdered } from "core/utils"
|
||||||
|
|
||||||
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
||||||
if ( examples && examples.size ) {
|
if ( examples && examples.size ) {
|
||||||
@@ -44,25 +45,39 @@ export default class Response extends React.Component {
|
|||||||
response: PropTypes.object,
|
response: PropTypes.object,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
fn: PropTypes.object.isRequired,
|
fn: PropTypes.object.isRequired,
|
||||||
contentType: PropTypes.string
|
contentType: PropTypes.string,
|
||||||
|
controlsAcceptHeader: PropTypes.bool,
|
||||||
|
onContentTypeChange: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
response: fromJS({}),
|
response: fromJS({}),
|
||||||
|
onContentTypeChange: () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_onContentTypeChange = (value) => {
|
||||||
|
const { onContentTypeChange, controlsAcceptHeader } = this.props
|
||||||
|
this.setState({ responseContentType: value })
|
||||||
|
onContentTypeChange({
|
||||||
|
value: value,
|
||||||
|
controlsAcceptHeader
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let {
|
let {
|
||||||
code,
|
code,
|
||||||
response,
|
response,
|
||||||
className,
|
className,
|
||||||
|
|
||||||
fn,
|
fn,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
contentType
|
contentType,
|
||||||
|
controlsAcceptHeader
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
let { inferSchema } = fn
|
let { inferSchema } = fn
|
||||||
@@ -94,6 +109,14 @@ export default class Response extends React.Component {
|
|||||||
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
||||||
}) : null
|
}) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(examples) {
|
||||||
|
examples = examples.map(example => {
|
||||||
|
// Remove unwanted properties from examples
|
||||||
|
return example.set ? example.set("$$ref", undefined) : example
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -107,17 +130,25 @@ export default class Response extends React.Component {
|
|||||||
<Markdown source={ response.get( "description" ) } />
|
<Markdown source={ response.get( "description" ) } />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ isOAS3 ? <ContentType
|
{ isOAS3 ?
|
||||||
|
<div className={cx("response-content-type", {
|
||||||
|
"controls-accept-header": controlsAcceptHeader
|
||||||
|
})}>
|
||||||
|
<ContentType
|
||||||
value={this.state.responseContentType}
|
value={this.state.responseContentType}
|
||||||
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() }
|
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() }
|
||||||
onChange={(val) => this.setState({ responseContentType: val })}
|
onChange={this._onContentTypeChange}
|
||||||
className="response-content-type" /> : null }
|
/>
|
||||||
|
{ controlsAcceptHeader ? <small>Controls <code>Accept</code> header.</small> : null }
|
||||||
|
</div>
|
||||||
|
: null }
|
||||||
|
|
||||||
{ example ? (
|
{ example ? (
|
||||||
<ModelExample
|
<ModelExample
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
schema={ fromJS(schema) }
|
schema={ fromJSOrdered(schema) }
|
||||||
example={ example }/>
|
example={ example }/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import { defaultStatusCode } from "core/utils"
|
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
|
||||||
|
|
||||||
export default class Responses extends React.Component {
|
export default class Responses extends React.Component {
|
||||||
|
|
||||||
@@ -12,8 +12,10 @@ export default class Responses extends React.Component {
|
|||||||
produces: PropTypes.object,
|
produces: PropTypes.object,
|
||||||
producesValue: PropTypes.any,
|
producesValue: PropTypes.any,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
pathMethod: PropTypes.array.isRequired,
|
pathMethod: PropTypes.array.isRequired,
|
||||||
displayRequestDuration: PropTypes.bool.isRequired,
|
displayRequestDuration: PropTypes.bool.isRequired,
|
||||||
fn: PropTypes.object.isRequired
|
fn: PropTypes.object.isRequired
|
||||||
@@ -28,8 +30,28 @@ export default class Responses extends React.Component {
|
|||||||
|
|
||||||
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
|
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
|
||||||
|
|
||||||
|
onResponseContentTypeChange = ({ controlsAcceptHeader, value }) => {
|
||||||
|
const { oas3Actions, pathMethod } = this.props
|
||||||
|
if(controlsAcceptHeader) {
|
||||||
|
oas3Actions.setResponseContentType({
|
||||||
|
value,
|
||||||
|
pathMethod
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { responses, request, tryItOutResponse, getComponent, specSelectors, fn, producesValue, displayRequestDuration } = this.props
|
let {
|
||||||
|
responses,
|
||||||
|
request,
|
||||||
|
tryItOutResponse,
|
||||||
|
getComponent,
|
||||||
|
getConfigs,
|
||||||
|
specSelectors,
|
||||||
|
fn,
|
||||||
|
producesValue,
|
||||||
|
displayRequestDuration
|
||||||
|
} = this.props
|
||||||
let defaultCode = defaultStatusCode( responses )
|
let defaultCode = defaultStatusCode( responses )
|
||||||
|
|
||||||
const ContentType = getComponent( "contentType" )
|
const ContentType = getComponent( "contentType" )
|
||||||
@@ -38,6 +60,11 @@ export default class Responses extends React.Component {
|
|||||||
|
|
||||||
let produces = this.props.produces && this.props.produces.size ? this.props.produces : Responses.defaultProps.produces
|
let produces = this.props.produces && this.props.produces.size ? this.props.produces : Responses.defaultProps.produces
|
||||||
|
|
||||||
|
const isSpecOAS3 = specSelectors.isOAS3()
|
||||||
|
|
||||||
|
const acceptControllingResponse = isSpecOAS3 ?
|
||||||
|
getAcceptControllingResponse(responses) : null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="responses-wrapper">
|
<div className="responses-wrapper">
|
||||||
<div className="opblock-section-header">
|
<div className="opblock-section-header">
|
||||||
@@ -57,6 +84,9 @@ export default class Responses extends React.Component {
|
|||||||
<LiveResponse request={ request }
|
<LiveResponse request={ request }
|
||||||
response={ tryItOutResponse }
|
response={ tryItOutResponse }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
|
specSelectors={ specSelectors }
|
||||||
|
pathMethod={ this.props.pathMethod }
|
||||||
displayRequestDuration={ displayRequestDuration } />
|
displayRequestDuration={ displayRequestDuration } />
|
||||||
<h4>Responses</h4>
|
<h4>Responses</h4>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,7 +104,6 @@ export default class Responses extends React.Component {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{
|
{
|
||||||
responses.entrySeq().map( ([code, response]) => {
|
responses.entrySeq().map( ([code, response]) => {
|
||||||
|
|
||||||
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
|
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
|
||||||
return (
|
return (
|
||||||
<Response key={ code }
|
<Response key={ code }
|
||||||
@@ -84,7 +113,10 @@ export default class Responses extends React.Component {
|
|||||||
code={ code }
|
code={ code }
|
||||||
response={ response }
|
response={ response }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
|
controlsAcceptHeader={response === acceptControllingResponse}
|
||||||
|
onContentTypeChange={this.onResponseContentTypeChange}
|
||||||
contentType={ producesValue }
|
contentType={ producesValue }
|
||||||
|
getConfigs={ getConfigs }
|
||||||
getComponent={ getComponent }/>
|
getComponent={ getComponent }/>
|
||||||
)
|
)
|
||||||
}).toArray()
|
}).toArray()
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
displayOperationId: false,
|
displayOperationId: false,
|
||||||
displayRequestDuration: false,
|
displayRequestDuration: false,
|
||||||
deepLinking: false,
|
deepLinking: false,
|
||||||
|
requestInterceptor: (a => a),
|
||||||
|
responseInterceptor: (a => a),
|
||||||
|
showMutatedRequest: true,
|
||||||
|
defaultModelRendering: "example",
|
||||||
|
defaultModelExpandDepth: 1,
|
||||||
|
|
||||||
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
// 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.
|
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
||||||
@@ -64,6 +69,9 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
|
|
||||||
let queryConfig = parseSearch()
|
let queryConfig = parseSearch()
|
||||||
|
|
||||||
|
const domNode = opts.domNode
|
||||||
|
delete opts.domNode
|
||||||
|
|
||||||
const constructorConfig = deepExtend({}, defaults, opts, queryConfig)
|
const constructorConfig = deepExtend({}, defaults, opts, queryConfig)
|
||||||
|
|
||||||
const storeConfigs = deepExtend({}, constructorConfig.store, {
|
const storeConfigs = deepExtend({}, constructorConfig.store, {
|
||||||
@@ -107,8 +115,8 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
||||||
|
|
||||||
// deep extend mangles domNode, we need to set it manually
|
// deep extend mangles domNode, we need to set it manually
|
||||||
if(opts.domNode) {
|
if(domNode) {
|
||||||
mergedConfig.domNode = opts.domNode
|
mergedConfig.domNode = domNode
|
||||||
}
|
}
|
||||||
|
|
||||||
store.setConfigs(mergedConfig)
|
store.setConfigs(mergedConfig)
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ export default function authorize ( { auth, authActions, errActions, configs, au
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = [schema.get("authorizationUrl"), query.join("&")].join("?")
|
let authorizationUrl = schema.get("authorizationUrl")
|
||||||
|
let url = [authorizationUrl, query.join("&")].join(authorizationUrl.indexOf("?") === -1 ? "?" : "&")
|
||||||
|
|
||||||
// pass action authorizeOauth2 and authentication data through window
|
// pass action authorizeOauth2 and authentication data through window
|
||||||
// to authorize with oauth2
|
// to authorize with oauth2
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { setHash } from "./helpers"
|
import { setHash } from "./helpers"
|
||||||
|
import { createDeepLinkPath } from "core/utils"
|
||||||
|
|
||||||
export const show = (ori, { getConfigs }) => (...args) => {
|
export const show = (ori, { getConfigs }) => (...args) => {
|
||||||
ori(...args)
|
ori(...args)
|
||||||
@@ -19,12 +20,12 @@ export const show = (ori, { getConfigs }) => (...args) => {
|
|||||||
|
|
||||||
if(type === "operations") {
|
if(type === "operations") {
|
||||||
let [, tag, operationId] = thing
|
let [, tag, operationId] = thing
|
||||||
setHash(`/${tag}/${operationId}`)
|
setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === "operations-tag") {
|
if(type === "operations-tag") {
|
||||||
let [, tag] = thing
|
let [, tag] = thing
|
||||||
setHash(`/${tag}`)
|
setHash(`/${createDeepLinkPath(tag)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import scrollTo from "scroll-to-element"
|
import scrollTo from "scroll-to-element"
|
||||||
|
import { escapeDeepLinkPath } from "core/utils"
|
||||||
|
|
||||||
const SCROLL_OFFSET = -5
|
const SCROLL_OFFSET = -5
|
||||||
let hasHashBeenParsed = false
|
let hasHashBeenParsed = false
|
||||||
@@ -34,14 +35,14 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
|
|||||||
layoutActions.show(["operations-tag", tag], true)
|
layoutActions.show(["operations-tag", tag], true)
|
||||||
layoutActions.show(["operations", tag, operationId], true)
|
layoutActions.show(["operations", tag, operationId], true)
|
||||||
|
|
||||||
scrollTo(`#operations-${tag}-${operationId}`, {
|
scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, {
|
||||||
offset: SCROLL_OFFSET
|
offset: SCROLL_OFFSET
|
||||||
})
|
})
|
||||||
} else if(tag) {
|
} else if(tag) {
|
||||||
// Pre-expand and scroll to the tag
|
// Pre-expand and scroll to the tag
|
||||||
layoutActions.show(["operations-tag", tag], true)
|
layoutActions.show(["operations-tag", tag], true)
|
||||||
|
|
||||||
scrollTo(`#operations-tag-${tag}`, {
|
scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, {
|
||||||
offset: SCROLL_OFFSET
|
offset: SCROLL_OFFSET
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/core/plugins/oas3/actions.js
Normal file
43
src/core/plugins/oas3/actions.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Actions conform to FSA (flux-standard-actions)
|
||||||
|
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
||||||
|
|
||||||
|
export const UPDATE_SELECTED_SERVER = "oas3_set_servers"
|
||||||
|
export const UPDATE_REQUEST_BODY_VALUE = "oas3_set_request_body_value"
|
||||||
|
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) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_SELECTED_SERVER,
|
||||||
|
payload: selectedServerUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setRequestBodyValue ({ value, pathMethod }) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_REQUEST_BODY_VALUE,
|
||||||
|
payload: { value, pathMethod }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setRequestContentType ({ value, pathMethod }) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_REQUEST_CONTENT_TYPE,
|
||||||
|
payload: { value, pathMethod }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setResponseContentType ({ value, pathMethod }) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_RESPONSE_CONTENT_TYPE,
|
||||||
|
payload: { value, pathMethod }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setServerVariableValue ({ server, key, val }) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_SERVER_VARIABLE_VALUE,
|
||||||
|
payload: { server, key, val }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import Callbacks from "./callbacks"
|
import Callbacks from "./callbacks"
|
||||||
import RequestBody from "./request-body"
|
import RequestBody from "./request-body"
|
||||||
import OperationLink from "./operation-link.jsx"
|
import OperationLink from "./operation-link.jsx"
|
||||||
|
import Servers from "./servers"
|
||||||
|
import RequestBodyEditor from "./request-body-editor"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Callbacks,
|
Callbacks,
|
||||||
RequestBody,
|
RequestBody,
|
||||||
|
Servers,
|
||||||
|
RequestBodyEditor,
|
||||||
operationLink: OperationLink
|
operationLink: OperationLink
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/core/plugins/oas3/components/request-body-editor.jsx
Normal file
114
src/core/plugins/oas3/components/request-body-editor.jsx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import React, { PureComponent } from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import { getSampleSchema } from "core/utils"
|
||||||
|
|
||||||
|
const NOOP = Function.prototype
|
||||||
|
|
||||||
|
export default class RequestBodyEditor extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
requestBody: PropTypes.object.isRequired,
|
||||||
|
mediaType: PropTypes.string.isRequired,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
isExecute: PropTypes.bool,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
mediaType: "application/json",
|
||||||
|
requestBody: fromJS({}),
|
||||||
|
onChange: NOOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isEditBox: false,
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.setValueToSample.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if(this.props.mediaType !== nextProps.mediaType) {
|
||||||
|
// media type was changed
|
||||||
|
this.setValueToSample(nextProps.mediaType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.props.isExecute && nextProps.isExecute) {
|
||||||
|
// we just entered execute mode,
|
||||||
|
// so enable editing for convenience
|
||||||
|
this.setState({ isEditBox: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValueToSample = (explicitMediaType) => {
|
||||||
|
this.onChange(this.sample(explicitMediaType))
|
||||||
|
}
|
||||||
|
|
||||||
|
sample = (explicitMediaType) => {
|
||||||
|
let { requestBody, mediaType } = this.props
|
||||||
|
let schema = requestBody.getIn(["content", explicitMediaType || mediaType, "schema"]).toJS()
|
||||||
|
|
||||||
|
return getSampleSchema(schema, explicitMediaType || mediaType, {
|
||||||
|
includeWriteOnly: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange = (value) => {
|
||||||
|
this.setState({value})
|
||||||
|
this.props.onChange(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnChange = e => {
|
||||||
|
const { mediaType } = this.props
|
||||||
|
const isJson = /json/i.test(mediaType)
|
||||||
|
const inputValue = isJson ? e.target.value.trim() : e.target.value
|
||||||
|
|
||||||
|
this.onChange(inputValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleIsEditBox = () => this.setState( state => ({isEditBox: !state.isEditBox}))
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let {
|
||||||
|
isExecute,
|
||||||
|
getComponent,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const Button = getComponent("Button")
|
||||||
|
const TextArea = getComponent("TextArea")
|
||||||
|
const HighlightCode = getComponent("highlightCode")
|
||||||
|
|
||||||
|
let { value, isEditBox } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="body-param">
|
||||||
|
{
|
||||||
|
isEditBox && isExecute
|
||||||
|
? <TextArea className={"body-param__text"} value={value} onChange={ this.handleOnChange }/>
|
||||||
|
: (value && <HighlightCode className="body-param__example"
|
||||||
|
value={ value }/>)
|
||||||
|
}
|
||||||
|
<div className="body-param-options">
|
||||||
|
{
|
||||||
|
!isExecute ? null
|
||||||
|
: <div className="body-param-edit">
|
||||||
|
<Button className={isEditBox ? "btn cancel body-param__example-edit" : "btn edit body-param__example-edit"}
|
||||||
|
onClick={this.toggleIsEditBox}>{ isEditBox ? "Cancel" : "Edit"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,18 @@ import React from "react"
|
|||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import ImPropTypes from "react-immutable-proptypes"
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
import { OrderedMap } from "immutable"
|
import { OrderedMap } from "immutable"
|
||||||
import { getSampleSchema } from "core/utils"
|
|
||||||
|
|
||||||
|
const RequestBody = ({
|
||||||
const RequestBody = ({ requestBody, getComponent, specSelectors, contentType }) => {
|
requestBody,
|
||||||
|
getComponent,
|
||||||
|
specSelectors,
|
||||||
|
contentType,
|
||||||
|
isExecute,
|
||||||
|
onChange
|
||||||
|
}) => {
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
const ModelExample = getComponent("modelExample")
|
const ModelExample = getComponent("modelExample")
|
||||||
const HighlightCode = getComponent("highlightCode")
|
const RequestBodyEditor = getComponent("RequestBodyEditor")
|
||||||
|
|
||||||
const requestBodyDescription = (requestBody && requestBody.get("description")) || null
|
const requestBodyDescription = (requestBody && requestBody.get("description")) || null
|
||||||
const requestBodyContent = (requestBody && requestBody.get("content")) || new OrderedMap()
|
const requestBodyContent = (requestBody && requestBody.get("content")) || new OrderedMap()
|
||||||
@@ -16,10 +21,6 @@ const RequestBody = ({ requestBody, getComponent, specSelectors, contentType })
|
|||||||
|
|
||||||
const mediaTypeValue = requestBodyContent.get(contentType)
|
const mediaTypeValue = requestBodyContent.get(contentType)
|
||||||
|
|
||||||
const sampleSchema = getSampleSchema(mediaTypeValue.get("schema").toJS(), contentType, {
|
|
||||||
includeWriteOnly: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
{ requestBodyDescription &&
|
{ requestBodyDescription &&
|
||||||
<Markdown source={requestBodyDescription} />
|
<Markdown source={requestBodyDescription} />
|
||||||
@@ -28,8 +29,16 @@ const RequestBody = ({ requestBody, getComponent, specSelectors, contentType })
|
|||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
specSelectors={ specSelectors }
|
specSelectors={ specSelectors }
|
||||||
expandDepth={1}
|
expandDepth={1}
|
||||||
|
isExecute={isExecute}
|
||||||
schema={mediaTypeValue.get("schema")}
|
schema={mediaTypeValue.get("schema")}
|
||||||
example={<HighlightCode value={sampleSchema} />}
|
example={<RequestBodyEditor
|
||||||
|
requestBody={requestBody}
|
||||||
|
onChange={onChange}
|
||||||
|
mediaType={contentType}
|
||||||
|
getComponent={getComponent}
|
||||||
|
isExecute={isExecute}
|
||||||
|
specSelectors={specSelectors}
|
||||||
|
/>}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -38,7 +47,9 @@ RequestBody.propTypes = {
|
|||||||
requestBody: ImPropTypes.orderedMap.isRequired,
|
requestBody: ImPropTypes.orderedMap.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
contentType: PropTypes.string.isRequired
|
contentType: PropTypes.string.isRequired,
|
||||||
|
isExecute: PropTypes.bool.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RequestBody
|
export default RequestBody
|
||||||
|
|||||||
155
src/core/plugins/oas3/components/servers.jsx
Normal file
155
src/core/plugins/oas3/components/servers.jsx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { OrderedMap } from "immutable"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
|
||||||
|
export default class Servers extends React.Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
servers: ImPropTypes.list.isRequired,
|
||||||
|
currentServer: PropTypes.string.isRequired,
|
||||||
|
setSelectedServer: PropTypes.func.isRequired,
|
||||||
|
setServerVariableValue: PropTypes.func.isRequired,
|
||||||
|
getServerVariable: PropTypes.func.isRequired,
|
||||||
|
getEffectiveServerValue: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let { servers } = this.props
|
||||||
|
|
||||||
|
//fire 'change' event to set default 'value' of select
|
||||||
|
this.setServer(servers.first().get("url"))
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
let {
|
||||||
|
servers,
|
||||||
|
setServerVariableValue,
|
||||||
|
getServerVariable
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
if(this.props.currentServer !== nextProps.currentServer) {
|
||||||
|
// Server has changed, we may need to set default values
|
||||||
|
let currentServerDefinition = servers
|
||||||
|
.find(v => v.get("url") === nextProps.currentServer) || OrderedMap()
|
||||||
|
|
||||||
|
let currentServerVariableDefs = currentServerDefinition.get("variables") || OrderedMap()
|
||||||
|
|
||||||
|
currentServerVariableDefs.map((val, key) => {
|
||||||
|
let currentValue = getServerVariable(nextProps.currentServer, key)
|
||||||
|
// only set the default value if the user hasn't set one yet
|
||||||
|
if(!currentValue) {
|
||||||
|
setServerVariableValue({
|
||||||
|
server: nextProps.currentServer,
|
||||||
|
key,
|
||||||
|
val: val.get("default") || ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onServerChange =( e ) => {
|
||||||
|
this.setServer( e.target.value )
|
||||||
|
|
||||||
|
// set default variable values
|
||||||
|
}
|
||||||
|
|
||||||
|
onServerVariableValueChange = ( e ) => {
|
||||||
|
let {
|
||||||
|
setServerVariableValue,
|
||||||
|
currentServer
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
let variableName = e.target.getAttribute("data-variable")
|
||||||
|
let newVariableValue = e.target.value
|
||||||
|
|
||||||
|
if(typeof setServerVariableValue === "function") {
|
||||||
|
setServerVariableValue({
|
||||||
|
server: currentServer,
|
||||||
|
key: variableName,
|
||||||
|
val: newVariableValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setServer = ( value ) => {
|
||||||
|
let { setSelectedServer } = this.props
|
||||||
|
|
||||||
|
setSelectedServer(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { servers,
|
||||||
|
currentServer,
|
||||||
|
getServerVariable,
|
||||||
|
getEffectiveServerValue
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
let currentServerDefinition = servers.find(v => v.get("url") === currentServer) || OrderedMap()
|
||||||
|
|
||||||
|
let currentServerVariableDefs = currentServerDefinition.get("variables") || OrderedMap()
|
||||||
|
|
||||||
|
let shouldShowVariableUI = currentServerVariableDefs.size !== 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label htmlFor="servers">
|
||||||
|
<span className="servers-title">Servers</span>
|
||||||
|
<select onChange={ this.onServerChange }>
|
||||||
|
{ servers.valueSeq().map(
|
||||||
|
( server ) =>
|
||||||
|
<option
|
||||||
|
value={ server.get("url") }
|
||||||
|
key={ server.get("url") }>
|
||||||
|
{ server.get("url") }
|
||||||
|
</option>
|
||||||
|
).toArray()}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
{ shouldShowVariableUI ?
|
||||||
|
<div>
|
||||||
|
<h4>Server variables</h4>
|
||||||
|
<div className={"computed-url"}>
|
||||||
|
Computed URL:
|
||||||
|
<code>
|
||||||
|
{getEffectiveServerValue(currentServer)}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{
|
||||||
|
currentServerVariableDefs.map((val, name) => {
|
||||||
|
return <tr key={name}>
|
||||||
|
<td>{name}</td>
|
||||||
|
<td>
|
||||||
|
{ val.get("enum") ?
|
||||||
|
<select data-variable={name} onChange={this.onServerVariableValueChange}>
|
||||||
|
{val.get("enum").map(enumValue => {
|
||||||
|
return <option
|
||||||
|
selected={enumValue === getServerVariable(currentServer, name)}
|
||||||
|
key={enumValue}
|
||||||
|
value={enumValue}>
|
||||||
|
{enumValue}
|
||||||
|
</option>
|
||||||
|
})}
|
||||||
|
</select> :
|
||||||
|
<input
|
||||||
|
type={"text"}
|
||||||
|
value={getServerVariable(currentServer, name) || ""}
|
||||||
|
onChange={this.onServerVariableValueChange}
|
||||||
|
data-variable={name}
|
||||||
|
></input>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>: null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
// import reducers from "./reducers"
|
// import reducers from "./reducers"
|
||||||
// import * as actions from "./actions"
|
// import * as actions from "./actions"
|
||||||
import * as wrapSelectors from "./wrap-selectors"
|
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
||||||
|
import * as specSelectors from "./spec-extensions/selectors"
|
||||||
import components from "./components"
|
import components from "./components"
|
||||||
import wrapComponents from "./wrap-components"
|
import wrapComponents from "./wrap-components"
|
||||||
|
import * as oas3Actions from "./actions"
|
||||||
|
import * as oas3Selectors from "./selectors"
|
||||||
|
import oas3Reducers from "./reducers"
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
return {
|
return {
|
||||||
@@ -10,7 +14,13 @@ export default function() {
|
|||||||
wrapComponents,
|
wrapComponents,
|
||||||
statePlugins: {
|
statePlugins: {
|
||||||
spec: {
|
spec: {
|
||||||
wrapSelectors
|
wrapSelectors: specWrapSelectors,
|
||||||
|
selectors: specSelectors
|
||||||
|
},
|
||||||
|
oas3: {
|
||||||
|
actions: oas3Actions,
|
||||||
|
reducers: oas3Reducers,
|
||||||
|
selectors: oas3Selectors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/core/plugins/oas3/reducers.js
Normal file
28
src/core/plugins/oas3/reducers.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
UPDATE_SELECTED_SERVER,
|
||||||
|
UPDATE_REQUEST_BODY_VALUE,
|
||||||
|
UPDATE_REQUEST_CONTENT_TYPE,
|
||||||
|
UPDATE_SERVER_VARIABLE_VALUE,
|
||||||
|
UPDATE_RESPONSE_CONTENT_TYPE
|
||||||
|
} from "./actions"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
[UPDATE_SELECTED_SERVER]: (state, { payload: selectedServerUrl } ) =>{
|
||||||
|
return state.setIn( [ "selectedServer" ], selectedServerUrl)
|
||||||
|
},
|
||||||
|
[UPDATE_REQUEST_BODY_VALUE]: (state, { payload: { value, pathMethod } } ) =>{
|
||||||
|
let [path, method] = pathMethod
|
||||||
|
return state.setIn( [ "requestData", path, method, "bodyValue" ], value)
|
||||||
|
},
|
||||||
|
[UPDATE_REQUEST_CONTENT_TYPE]: (state, { payload: { value, pathMethod } } ) =>{
|
||||||
|
let [path, method] = pathMethod
|
||||||
|
return state.setIn( [ "requestData", path, method, "requestContentType" ], value)
|
||||||
|
},
|
||||||
|
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, pathMethod } } ) =>{
|
||||||
|
let [path, method] = pathMethod
|
||||||
|
return state.setIn( [ "requestData", path, method, "responseContentType" ], value)
|
||||||
|
},
|
||||||
|
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{
|
||||||
|
return state.setIn( [ "serverVariableValues", server, key ], val)
|
||||||
|
},
|
||||||
|
}
|
||||||
58
src/core/plugins/oas3/selectors.js
Normal file
58
src/core/plugins/oas3/selectors.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { OrderedMap } from "immutable"
|
||||||
|
import { isOAS3 as isOAS3Helper } from "./helpers"
|
||||||
|
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
function onlyOAS3(selector) {
|
||||||
|
return (...args) => (system) => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
if(isOAS3Helper(spec)) {
|
||||||
|
return selector(...args)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const selectedServer = onlyOAS3(state => {
|
||||||
|
return state.getIn(["selectedServer"]) || ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const requestBodyValue = onlyOAS3((state, path, method) => {
|
||||||
|
return state.getIn(["requestData", path, method, "bodyValue"]) || null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const requestContentType = onlyOAS3((state, path, method) => {
|
||||||
|
return state.getIn(["requestData", path, method, "requestContentType"]) || null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const responseContentType = onlyOAS3((state, path, method) => {
|
||||||
|
return state.getIn(["requestData", path, method, "responseContentType"]) || null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const serverVariableValue = onlyOAS3((state, server, key) => {
|
||||||
|
return state.getIn(["serverVariableValues", server, key]) || null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const serverVariables = onlyOAS3((state, server) => {
|
||||||
|
return state.getIn(["serverVariableValues", server]) || OrderedMap()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const serverEffectiveValue = onlyOAS3((state, server) => {
|
||||||
|
let varValues = state.getIn(["serverVariableValues", server]) || OrderedMap()
|
||||||
|
let str = server
|
||||||
|
|
||||||
|
varValues.map((val, key) => {
|
||||||
|
str = str.replace(new RegExp(`{${key}}`, "g"), val)
|
||||||
|
})
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
)
|
||||||
50
src/core/plugins/oas3/spec-extensions/selectors.js
Normal file
50
src/core/plugins/oas3/spec-extensions/selectors.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { createSelector } from "reselect"
|
||||||
|
import { Map } from "immutable"
|
||||||
|
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
|
||||||
|
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
function onlyOAS3(selector) {
|
||||||
|
return () => (system, ...args) => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
if(isOAS3Helper(spec)) {
|
||||||
|
return selector(...args)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = state => {
|
||||||
|
return state || Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
const specJson = createSelector(
|
||||||
|
state,
|
||||||
|
spec => spec.get("json", Map())
|
||||||
|
)
|
||||||
|
|
||||||
|
const specResolved = createSelector(
|
||||||
|
state,
|
||||||
|
spec => spec.get("resolved", Map())
|
||||||
|
)
|
||||||
|
|
||||||
|
const spec = state => {
|
||||||
|
let res = specResolved(state)
|
||||||
|
if(res.count() < 1)
|
||||||
|
res = specJson(state)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// New selectors
|
||||||
|
|
||||||
|
export const servers = onlyOAS3(createSelector(
|
||||||
|
spec,
|
||||||
|
spec => spec.getIn(["servers"]) || Map()
|
||||||
|
))
|
||||||
|
|
||||||
|
export const isSwagger2 = (ori, system) => () => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
return isSwagger2Helper(spec)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createSelector } from "reselect"
|
import { createSelector } from "reselect"
|
||||||
import { Map } from "immutable"
|
import { Map } from "immutable"
|
||||||
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "./helpers"
|
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "../helpers"
|
||||||
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -56,6 +56,11 @@ export const schemes = OAS3NullSelector
|
|||||||
|
|
||||||
// New selectors
|
// New selectors
|
||||||
|
|
||||||
|
export const servers = onlyOAS3(createSelector(
|
||||||
|
spec,
|
||||||
|
spec => spec.getIn(["servers"]) || Map()
|
||||||
|
))
|
||||||
|
|
||||||
export const isOAS3 = (ori, system) => () => {
|
export const isOAS3 = (ori, system) => () => {
|
||||||
const spec = system.getSystem().specSelectors.specJson()
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
return isOAS3Helper(spec)
|
return isOAS3Helper(spec)
|
||||||
@@ -3,7 +3,6 @@ import parameters from "./parameters"
|
|||||||
import VersionStamp from "./version-stamp"
|
import VersionStamp from "./version-stamp"
|
||||||
import OnlineValidatorBadge from "./online-validator-badge"
|
import OnlineValidatorBadge from "./online-validator-badge"
|
||||||
import Model from "./model"
|
import Model from "./model"
|
||||||
import TryItOutButton from "./try-it-out-button"
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Markdown,
|
Markdown,
|
||||||
@@ -11,5 +10,4 @@ export default {
|
|||||||
VersionStamp,
|
VersionStamp,
|
||||||
model: Model,
|
model: Model,
|
||||||
onlineValidatorBadge: OnlineValidatorBadge,
|
onlineValidatorBadge: OnlineValidatorBadge,
|
||||||
TryItOutButton
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import ReactMarkdown from "react-markdown"
|
import ReactMarkdown from "react-markdown"
|
||||||
|
import { Parser, HtmlRenderer } from "commonmark"
|
||||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
import { sanitizer } from "core/components/providers/markdown"
|
import { sanitizer } from "core/components/providers/markdown"
|
||||||
|
|
||||||
export default OAS3ComponentWrapFactory(({ source }) => { return source ? (
|
export default OAS3ComponentWrapFactory(({ source }) => {
|
||||||
|
if ( source ) {
|
||||||
|
const parser = new Parser()
|
||||||
|
const writer = new HtmlRenderer()
|
||||||
|
const html = writer.render(parser.parse(source || ""))
|
||||||
|
const sanitized = sanitizer(html)
|
||||||
|
|
||||||
|
if ( !source || !html || !sanitized ) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
source={sanitizer(source)}
|
source={sanitized}
|
||||||
className={"renderedMarkdown"}
|
className={"renderedMarkdown"}
|
||||||
/>
|
/>
|
||||||
) : null})
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
@@ -13,8 +13,7 @@ class Parameters extends Component {
|
|||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
callbackVisible: false,
|
callbackVisible: false,
|
||||||
parametersVisible: true,
|
parametersVisible: true
|
||||||
requestBodyContentType: ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +23,8 @@ class Parameters extends Component {
|
|||||||
operation: PropTypes.object.isRequired,
|
operation: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
specSelectors: PropTypes.object.isRequired,
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
oas3Actions: PropTypes.object.isRequired,
|
||||||
|
oas3Selectors: PropTypes.object.isRequired,
|
||||||
fn: PropTypes.object.isRequired,
|
fn: PropTypes.object.isRequired,
|
||||||
tryItOutEnabled: PropTypes.bool,
|
tryItOutEnabled: PropTypes.bool,
|
||||||
allowTryItOut: PropTypes.bool,
|
allowTryItOut: PropTypes.bool,
|
||||||
@@ -48,7 +49,7 @@ class Parameters extends Component {
|
|||||||
onChangeKey,
|
onChangeKey,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
changeParam( onChangeKey, param.get("name"), value, isXml)
|
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeConsumesWrapper = ( val ) => {
|
onChangeConsumesWrapper = ( val ) => {
|
||||||
@@ -86,6 +87,8 @@ class Parameters extends Component {
|
|||||||
fn,
|
fn,
|
||||||
getComponent,
|
getComponent,
|
||||||
specSelectors,
|
specSelectors,
|
||||||
|
oas3Actions,
|
||||||
|
oas3Selectors,
|
||||||
pathMethod,
|
pathMethod,
|
||||||
operation
|
operation
|
||||||
} = this.props
|
} = this.props
|
||||||
@@ -159,16 +162,22 @@ class Parameters extends Component {
|
|||||||
<h4 className={`opblock-title parameter__name ${requestBody.get("required") && "required"}`}>Request body</h4>
|
<h4 className={`opblock-title parameter__name ${requestBody.get("required") && "required"}`}>Request body</h4>
|
||||||
<label>
|
<label>
|
||||||
<ContentType
|
<ContentType
|
||||||
value={this.state.requestBodyContentType}
|
value={oas3Selectors.requestContentType(...pathMethod)}
|
||||||
contentTypes={ requestBody.get("content").keySeq() }
|
contentTypes={ requestBody.get("content").keySeq() }
|
||||||
onChange={(val) => this.setState({ requestBodyContentType: val })}
|
onChange={(value) => {
|
||||||
|
oas3Actions.setRequestContentType({ value, pathMethod })
|
||||||
|
}}
|
||||||
className="body-param-content-type" />
|
className="body-param-content-type" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="opblock-description-wrapper">
|
<div className="opblock-description-wrapper">
|
||||||
<RequestBody
|
<RequestBody
|
||||||
requestBody={requestBody}
|
requestBody={requestBody}
|
||||||
contentType={this.state.requestBodyContentType}/>
|
isExecute={isExecute}
|
||||||
|
onChange={(value) => {
|
||||||
|
oas3Actions.setRequestBodyValue({ value, pathMethod })
|
||||||
|
}}
|
||||||
|
contentType={oas3Selectors.requestContentType(...pathMethod)}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
|
||||||
|
|
||||||
export default OAS3ComponentWrapFactory(() => {
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import YAML from "js-yaml"
|
import YAML from "js-yaml"
|
||||||
import parseUrl from "url-parse"
|
import parseUrl from "url-parse"
|
||||||
import serializeError from "serialize-error"
|
import serializeError from "serialize-error"
|
||||||
|
import { isJSONObject } from "core/utils"
|
||||||
|
|
||||||
// Actions conform to FSA (flux-standard-actions)
|
// Actions conform to FSA (flux-standard-actions)
|
||||||
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
||||||
@@ -12,6 +13,7 @@ export const UPDATE_PARAM = "spec_update_param"
|
|||||||
export const VALIDATE_PARAMS = "spec_validate_param"
|
export const VALIDATE_PARAMS = "spec_validate_param"
|
||||||
export const SET_RESPONSE = "spec_set_response"
|
export const SET_RESPONSE = "spec_set_response"
|
||||||
export const SET_REQUEST = "spec_set_request"
|
export const SET_REQUEST = "spec_set_request"
|
||||||
|
export const SET_MUTATED_REQUEST = "spec_set_mutated_request"
|
||||||
export const LOG_REQUEST = "spec_log_request"
|
export const LOG_REQUEST = "spec_log_request"
|
||||||
export const CLEAR_RESPONSE = "spec_clear_response"
|
export const CLEAR_RESPONSE = "spec_clear_response"
|
||||||
export const CLEAR_REQUEST = "spec_clear_request"
|
export const CLEAR_REQUEST = "spec_clear_request"
|
||||||
@@ -128,10 +130,10 @@ export const formatIntoYaml = () => ({specActions, specSelectors}) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeParam( path, paramName, value, isXml ){
|
export function changeParam( path, paramName, paramIn, value, isXml ){
|
||||||
return {
|
return {
|
||||||
type: UPDATE_PARAM,
|
type: UPDATE_PARAM,
|
||||||
payload:{ path, value, paramName, isXml }
|
payload:{ path, value, paramName, paramIn, isXml }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,6 +179,13 @@ export const setRequest = ( path, method, req ) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const setMutatedRequest = ( path, method, req ) => {
|
||||||
|
return {
|
||||||
|
payload: { path, method, req },
|
||||||
|
type: SET_MUTATED_REQUEST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is for debugging, remove this comment if you depend on this action
|
// This is for debugging, remove this comment if you depend on this action
|
||||||
export const logRequest = (req) => {
|
export const logRequest = (req) => {
|
||||||
return {
|
return {
|
||||||
@@ -187,26 +196,52 @@ export const logRequest = (req) => {
|
|||||||
|
|
||||||
// Actually fire the request via fn.execute
|
// Actually fire the request via fn.execute
|
||||||
// (For debugging) and ease of testing
|
// (For debugging) and ease of testing
|
||||||
export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
|
export const executeRequest = (req) =>
|
||||||
|
({fn, specActions, specSelectors, getConfigs, oas3Selectors}) => {
|
||||||
let { pathName, method, operation } = req
|
let { pathName, method, operation } = req
|
||||||
|
let { requestInterceptor, responseInterceptor } = getConfigs()
|
||||||
|
|
||||||
let op = operation.toJS()
|
let op = operation.toJS()
|
||||||
|
|
||||||
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
|
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
|
||||||
req.contextUrl = parseUrl(specSelectors.url()).toString()
|
req.contextUrl = parseUrl(specSelectors.url()).toString()
|
||||||
|
|
||||||
|
|
||||||
if(op && op.operationId) {
|
if(op && op.operationId) {
|
||||||
req.operationId = op.operationId
|
req.operationId = op.operationId
|
||||||
} else if(op && pathName && method) {
|
} else if(op && pathName && method) {
|
||||||
req.operationId = fn.opId(op, pathName, method)
|
req.operationId = fn.opId(op, pathName, method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(specSelectors.isOAS3()) {
|
||||||
|
// OAS3 request feature support
|
||||||
|
req.server = oas3Selectors.selectedServer()
|
||||||
|
req.serverVariables = oas3Selectors.serverVariables(req.server).toJS()
|
||||||
|
req.requestContentType = oas3Selectors.requestContentType(pathName, method)
|
||||||
|
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
|
||||||
|
const requestBody = oas3Selectors.requestBodyValue(pathName, method)
|
||||||
|
|
||||||
|
if(isJSONObject(requestBody)) {
|
||||||
|
req.requestBody = JSON.parse(requestBody)
|
||||||
|
} else {
|
||||||
|
req.requestBody = requestBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let parsedRequest = Object.assign({}, req)
|
let parsedRequest = Object.assign({}, req)
|
||||||
parsedRequest = fn.buildRequest(parsedRequest)
|
parsedRequest = fn.buildRequest(parsedRequest)
|
||||||
|
|
||||||
specActions.setRequest(req.pathName, req.method, parsedRequest)
|
specActions.setRequest(req.pathName, req.method, parsedRequest)
|
||||||
|
|
||||||
|
let requestInterceptorWrapper = function(r) {
|
||||||
|
let mutatedRequest = requestInterceptor.apply(this, [r])
|
||||||
|
let parsedMutatedRequest = Object.assign({}, mutatedRequest)
|
||||||
|
specActions.setMutatedRequest(req.pathName, req.method, parsedMutatedRequest)
|
||||||
|
return mutatedRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
req.requestInterceptor = requestInterceptorWrapper
|
||||||
|
req.responseInterceptor = responseInterceptor
|
||||||
|
|
||||||
// track duration of request
|
// track duration of request
|
||||||
const startTime = Date.now()
|
const startTime = Date.now()
|
||||||
|
|
||||||
@@ -215,7 +250,11 @@ export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
|
|||||||
res.duration = Date.now() - startTime
|
res.duration = Date.now() - startTime
|
||||||
specActions.setResponse(req.pathName, req.method, res)
|
specActions.setResponse(req.pathName, req.method, res)
|
||||||
} )
|
} )
|
||||||
.catch( err => specActions.setResponse(req.pathName, req.method, { error: true, err: serializeError(err) } ) )
|
.catch(
|
||||||
|
err => specActions.setResponse(req.pathName, req.method, {
|
||||||
|
error: true, err: serializeError(err)
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
VALIDATE_PARAMS,
|
VALIDATE_PARAMS,
|
||||||
SET_RESPONSE,
|
SET_RESPONSE,
|
||||||
SET_REQUEST,
|
SET_REQUEST,
|
||||||
|
SET_MUTATED_REQUEST,
|
||||||
UPDATE_RESOLVED,
|
UPDATE_RESOLVED,
|
||||||
UPDATE_OPERATION_VALUE,
|
UPDATE_OPERATION_VALUE,
|
||||||
CLEAR_RESPONSE,
|
CLEAR_RESPONSE,
|
||||||
@@ -39,9 +40,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[UPDATE_PARAM]: ( state, {payload} ) => {
|
[UPDATE_PARAM]: ( state, {payload} ) => {
|
||||||
let { path, paramName, value, isXml } = payload
|
let { path, paramName, paramIn, value, isXml } = payload
|
||||||
|
|
||||||
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
|
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
|
||||||
const index = parameters.findIndex(p => p.get( "name" ) === paramName )
|
const index = parameters.findIndex(p => p.get( "name" ) === paramName && p.get("in") === paramIn )
|
||||||
if (!(value instanceof win.File)) {
|
if (!(value instanceof win.File)) {
|
||||||
value = fromJSOrdered( value )
|
value = fromJSOrdered( value )
|
||||||
}
|
}
|
||||||
@@ -101,6 +103,10 @@ export default {
|
|||||||
return state.setIn( [ "requests", path, method ], fromJSOrdered(req))
|
return state.setIn( [ "requests", path, method ], fromJSOrdered(req))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[SET_MUTATED_REQUEST]: (state, { payload: { req, path, method } } ) =>{
|
||||||
|
return state.setIn( [ "mutatedRequests", path, method ], fromJSOrdered(req))
|
||||||
|
},
|
||||||
|
|
||||||
[UPDATE_OPERATION_VALUE]: (state, { payload: { path, value, key } }) => {
|
[UPDATE_OPERATION_VALUE]: (state, { payload: { path, value, key } }) => {
|
||||||
let operationPath = ["resolved", "paths", ...path]
|
let operationPath = ["resolved", "paths", ...path]
|
||||||
if(!state.getIn(operationPath)) {
|
if(!state.getIn(operationPath)) {
|
||||||
|
|||||||
@@ -237,6 +237,11 @@ export const requests = createSelector(
|
|||||||
state => state.get( "requests", Map() )
|
state => state.get( "requests", Map() )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const mutatedRequests = createSelector(
|
||||||
|
state,
|
||||||
|
state => state.get( "mutatedRequests", Map() )
|
||||||
|
)
|
||||||
|
|
||||||
export const responseFor = (state, path, method) => {
|
export const responseFor = (state, path, method) => {
|
||||||
return responses(state).getIn([path, method], null)
|
return responses(state).getIn([path, method], null)
|
||||||
}
|
}
|
||||||
@@ -245,16 +250,20 @@ export const requestFor = (state, path, method) => {
|
|||||||
return requests(state).getIn([path, method], null)
|
return requests(state).getIn([path, method], null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mutatedRequestFor = (state, path, method) => {
|
||||||
|
return mutatedRequests(state).getIn([path, method], null)
|
||||||
|
}
|
||||||
|
|
||||||
export const allowTryItOutFor = () => {
|
export const allowTryItOutFor = () => {
|
||||||
// This is just a hook for now.
|
// This is just a hook for now.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the parameter value by parameter name
|
// Get the parameter value by parameter name
|
||||||
export function getParameter(state, pathMethod, name) {
|
export function getParameter(state, pathMethod, name, inType) {
|
||||||
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
||||||
return params.filter( (p) => {
|
return params.filter( (p) => {
|
||||||
return Map.isMap(p) && p.get("name") === name
|
return Map.isMap(p) && p.get("name") === name && p.get("in") === inType
|
||||||
}).first()
|
}).first()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +280,7 @@ export function parameterValues(state, pathMethod, isXml) {
|
|||||||
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
|
||||||
return params.reduce( (hash, p) => {
|
return params.reduce( (hash, p) => {
|
||||||
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
||||||
return hash.set(p.get("name"), value)
|
return hash.set(`${p.get("in")}.${p.get("name")}`, value)
|
||||||
}, fromJS({}))
|
}, fromJS({}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,31 @@ import some from "lodash/some"
|
|||||||
import eq from "lodash/eq"
|
import eq from "lodash/eq"
|
||||||
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
|
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
|
||||||
import win from "./window"
|
import win from "./window"
|
||||||
|
import cssEscape from "css.escape"
|
||||||
|
|
||||||
const DEFAULT_REPONSE_KEY = "default"
|
const DEFAULT_REPONSE_KEY = "default"
|
||||||
|
|
||||||
export const isImmutable = (maybe) => Im.Iterable.isIterable(maybe)
|
export const isImmutable = (maybe) => Im.Iterable.isIterable(maybe)
|
||||||
|
|
||||||
|
export function isJSONObject (str) {
|
||||||
|
try {
|
||||||
|
var o = JSON.parse(str)
|
||||||
|
|
||||||
|
// Handle non-exception-throwing cases:
|
||||||
|
// Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
|
||||||
|
// but... JSON.parse(null) returns null, and typeof null === "object",
|
||||||
|
// so we must check for that, too. Thankfully, null is falsey, so this suffices:
|
||||||
|
if (o && typeof o === "object") {
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
export function objectify (thing) {
|
export function objectify (thing) {
|
||||||
if(!isObject(thing))
|
if(!isObject(thing))
|
||||||
return {}
|
return {}
|
||||||
@@ -450,6 +470,18 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|
|||||||
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
|
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateMaximum = ( val, max ) => {
|
||||||
|
if (val > max) {
|
||||||
|
return "Value must be less than Maximum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMinimum = ( val, min ) => {
|
||||||
|
if (val < min) {
|
||||||
|
return "Value must be greater than Minimum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const validateNumber = ( val ) => {
|
export const validateNumber = ( val ) => {
|
||||||
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
||||||
return "Value must be a number"
|
return "Value must be a number"
|
||||||
@@ -480,12 +512,41 @@ export const validateString = ( val ) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateDateTime = (val) => {
|
||||||
|
if (isNaN(Date.parse(val))) {
|
||||||
|
return "Value must be a DateTime"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateGuid = (val) => {
|
||||||
|
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
|
||||||
|
return "Value must be a Guid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMaxLength = (val, max) => {
|
||||||
|
if (val.length > max) {
|
||||||
|
return "Value must be less than MaxLength"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateMinLength = (val, min) => {
|
||||||
|
if (val.length < min) {
|
||||||
|
return "Value must be greater than MinLength"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validation of parameters before execute
|
// validation of parameters before execute
|
||||||
export const validateParam = (param, isXml) => {
|
export const validateParam = (param, isXml) => {
|
||||||
let errors = []
|
let errors = []
|
||||||
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
|
let maximum = param.get("maximum")
|
||||||
|
let minimum = param.get("minimum")
|
||||||
let type = param.get("type")
|
let type = param.get("type")
|
||||||
|
let format = param.get("format")
|
||||||
|
let maxLength = param.get("maxLength")
|
||||||
|
let minLength = param.get("minLength")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
||||||
@@ -502,13 +563,40 @@ export const validateParam = (param, isXml) => {
|
|||||||
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
||||||
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
||||||
|
|
||||||
|
if (maxLength || maxLength === 0) {
|
||||||
|
let err = validateMaxLength(value, maxLength)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minLength) {
|
||||||
|
let err = validateMinLength(value, minLength)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
||||||
errors.push("Required field is not provided")
|
errors.push("Required field is not provided")
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maximum || maximum === 0) {
|
||||||
|
let err = validateMaximum(value, maximum)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minimum || minimum === 0) {
|
||||||
|
let err = validateMinimum(value, minimum)
|
||||||
|
if (err) errors.push(err)
|
||||||
|
}
|
||||||
|
|
||||||
if ( type === "string" ) {
|
if ( type === "string" ) {
|
||||||
let err = validateString(value)
|
let err
|
||||||
|
if (format === "date-time") {
|
||||||
|
err = validateDateTime(value)
|
||||||
|
} else if (format === "uuid") {
|
||||||
|
err = validateGuid(value)
|
||||||
|
} else {
|
||||||
|
err = validateString(value)
|
||||||
|
}
|
||||||
if (!err) return errors
|
if (!err) return errors
|
||||||
errors.push(err)
|
errors.push(err)
|
||||||
} else if ( type === "boolean" ) {
|
} else if ( type === "boolean" ) {
|
||||||
@@ -631,3 +719,29 @@ export const shallowEqualKeys = (a,b, keys) => {
|
|||||||
return eq(a[key], b[key])
|
return eq(a[key], b[key])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAcceptControllingResponse(responses) {
|
||||||
|
if(!Im.OrderedMap.isOrderedMap(responses)) {
|
||||||
|
// wrong type!
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!responses.size) {
|
||||||
|
// responses is empty
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const suitable2xxResponse = responses.find((res, k) => {
|
||||||
|
return k.startsWith("2") && Object.keys(res.get("content") || {}).length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// try to find a suitable `default` responses
|
||||||
|
const defaultResponse = responses.get("default") || Im.OrderedMap()
|
||||||
|
const defaultResponseMediaTypes = (defaultResponse.get("content") || Im.OrderedMap()).keySeq().toJS()
|
||||||
|
const suitableDefaultResponse = defaultResponseMediaTypes.length ? defaultResponse : null
|
||||||
|
|
||||||
|
return suitable2xxResponse || suitableDefaultResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createDeepLinkPath = (str) => typeof str == "string" || str instanceof String ? str.trim().replace(/\s/g, "_") : ""
|
||||||
|
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
|
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
|
||||||
|
|
||||||
|
if(!window.Promise) {
|
||||||
require("core-js/fn/promise")
|
require("core-js/fn/promise")
|
||||||
|
}
|
||||||
|
|||||||
@@ -252,8 +252,11 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 3 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|
||||||
@include text_code();
|
@include text_code();
|
||||||
@@ -636,6 +639,77 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.server-container
|
||||||
|
{
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
padding: 30px 0;
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0,0,0,.15);
|
||||||
|
|
||||||
|
.computed-url {
|
||||||
|
margin: 2em 0;
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: grey;
|
||||||
|
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
|
.loading-container
|
||||||
{
|
{
|
||||||
@@ -704,6 +778,17 @@
|
|||||||
|
|
||||||
.response-content-type {
|
.response-content-type {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
|
|
||||||
|
&.controls-accept-header {
|
||||||
|
select {
|
||||||
|
border-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
color: green;
|
||||||
|
font-size: .7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes blinker
|
@keyframes blinker
|
||||||
@@ -726,12 +811,12 @@ section
|
|||||||
a.nostyle {
|
a.nostyle {
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
cursor: auto;
|
cursor: pointer;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|
||||||
&:visited {
|
&:visited {
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
cursor: auto;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ span
|
|||||||
.prop-name
|
.prop-name
|
||||||
{
|
{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100px;
|
margin-right: 1em;
|
||||||
|
width: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prop-type
|
.prop-type
|
||||||
|
|||||||
85
test/components/live-response.js
Normal file
85
test/components/live-response.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import { fromJSOrdered } from "core/utils"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import Curl from "components/curl"
|
||||||
|
import LiveResponse from "components/live-response"
|
||||||
|
import ResponseBody from "components/response-body"
|
||||||
|
|
||||||
|
describe("<LiveResponse/>", function(){
|
||||||
|
let request = fromJSOrdered({
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: {
|
||||||
|
accept: "application/xml"
|
||||||
|
},
|
||||||
|
url: "http://petstore.swagger.io/v2/pet/1"
|
||||||
|
})
|
||||||
|
|
||||||
|
let mutatedRequest = fromJSOrdered({
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: {
|
||||||
|
accept: "application/xml",
|
||||||
|
mutated: "header"
|
||||||
|
},
|
||||||
|
url: "http://petstore.swagger.io/v2/pet/1"
|
||||||
|
})
|
||||||
|
|
||||||
|
let requests = {
|
||||||
|
request: request,
|
||||||
|
mutatedRequest: mutatedRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const tests = [
|
||||||
|
{ showMutatedRequest: true, expected: { request: "mutatedRequest", requestForCalls: 0, mutatedRequestForCalls: 1 } },
|
||||||
|
{ showMutatedRequest: false, expected: { request: "request", requestForCalls: 1, mutatedRequestForCalls: 0 } }
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(test) {
|
||||||
|
it("passes " + test.expected.request + " to Curl when showMutatedRequest = " + test.showMutatedRequest, function() {
|
||||||
|
|
||||||
|
// Given
|
||||||
|
|
||||||
|
let response = fromJSOrdered({
|
||||||
|
status: 200,
|
||||||
|
url: "http://petstore.swagger.io/v2/pet/1",
|
||||||
|
headers: {},
|
||||||
|
text: "<response/>",
|
||||||
|
})
|
||||||
|
|
||||||
|
let mutatedRequestForSpy = createSpy().andReturn(mutatedRequest)
|
||||||
|
let requestForSpy = createSpy().andReturn(request)
|
||||||
|
|
||||||
|
let components = {
|
||||||
|
curl: Curl,
|
||||||
|
responseBody: ResponseBody
|
||||||
|
}
|
||||||
|
|
||||||
|
let props = {
|
||||||
|
response: response,
|
||||||
|
specSelectors: {
|
||||||
|
mutatedRequestFor: mutatedRequestForSpy,
|
||||||
|
requestFor: requestForSpy,
|
||||||
|
},
|
||||||
|
pathMethod: [ "/one", "get" ],
|
||||||
|
getComponent: (c) => {
|
||||||
|
return components[c]
|
||||||
|
},
|
||||||
|
displayRequestDuration: true,
|
||||||
|
getConfigs: () => ({ showMutatedRequest: test.showMutatedRequest })
|
||||||
|
}
|
||||||
|
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<LiveResponse {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(mutatedRequestForSpy.calls.length).toEqual(test.expected.mutatedRequestForCalls)
|
||||||
|
expect(requestForSpy.calls.length).toEqual(test.expected.requestForCalls)
|
||||||
|
|
||||||
|
const curl = wrapper.find(Curl)
|
||||||
|
expect(curl.length).toEqual(1)
|
||||||
|
expect(curl.props().request).toBe(requests[test.expected.request])
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
116
test/components/model-example.js
Normal file
116
test/components/model-example.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import ModelExample from "components/model-example"
|
||||||
|
import ModelComponent from "components/model-wrapper"
|
||||||
|
|
||||||
|
describe("<ModelExample/>", function(){
|
||||||
|
// Given
|
||||||
|
let components = {
|
||||||
|
ModelWrapper: ModelComponent
|
||||||
|
}
|
||||||
|
let props = {
|
||||||
|
getComponent: (c) => {
|
||||||
|
return components[c]
|
||||||
|
},
|
||||||
|
specSelectors: {},
|
||||||
|
schema: {},
|
||||||
|
example: "{\"example\": \"value\"}",
|
||||||
|
isExecute: false,
|
||||||
|
getConfigs: () => ({
|
||||||
|
defaultModelRendering: "model",
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let exampleSelectedTestInputs = [
|
||||||
|
{ defaultModelRendering: "model", isExecute: true },
|
||||||
|
{ defaultModelRendering: "example", isExecute: true },
|
||||||
|
{ defaultModelRendering: "example", isExecute: false },
|
||||||
|
{ defaultModelRendering: "othervalue", isExecute: true },
|
||||||
|
{ defaultModelRendering: "othervalue", isExecute: false }
|
||||||
|
]
|
||||||
|
let modelSelectedTestInputs = [
|
||||||
|
{ defaultModelRendering: "model", isExecute: false }
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
it("renders model and example tabs", function(){
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then should render tabs
|
||||||
|
expect(wrapper.find("div > ul.tab").length).toEqual(1)
|
||||||
|
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
expect(tabs.length).toEqual(2)
|
||||||
|
tabs.forEach((node) => {
|
||||||
|
expect(node.length).toEqual(1)
|
||||||
|
expect(node.name()).toEqual("li")
|
||||||
|
expect(node.hasClass("tabitem")).toEqual(true)
|
||||||
|
})
|
||||||
|
expect(tabs.at(0).text()).toEqual("Example Value")
|
||||||
|
expect(tabs.at(1).text()).toEqual("Model")
|
||||||
|
})
|
||||||
|
|
||||||
|
exampleSelectedTestInputs.forEach(function(testInputs) {
|
||||||
|
it("example tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||||
|
// When
|
||||||
|
props.isExecute = testInputs.isExecute
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: testInputs.defaultModelRendering,
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
|
||||||
|
let exampleTab = tabs.at(0)
|
||||||
|
expect(exampleTab.hasClass("active")).toEqual(true)
|
||||||
|
let modelTab = tabs.at(1)
|
||||||
|
expect(modelTab.hasClass("active")).toEqual(false)
|
||||||
|
|
||||||
|
expect(wrapper.find("div > div").length).toEqual(1)
|
||||||
|
expect(wrapper.find("div > div").text()).toEqual(props.example)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
modelSelectedTestInputs.forEach(function(testInputs) {
|
||||||
|
it("model tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||||
|
// When
|
||||||
|
props.isExecute = testInputs.isExecute
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: testInputs.defaultModelRendering,
|
||||||
|
defaultModelExpandDepth: 1
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
let tabs = wrapper.find("div > ul.tab").children()
|
||||||
|
|
||||||
|
let exampleTab = tabs.at(0)
|
||||||
|
expect(exampleTab.hasClass("active")).toEqual(false)
|
||||||
|
let modelTab = tabs.at(1)
|
||||||
|
expect(modelTab.hasClass("active")).toEqual(true)
|
||||||
|
|
||||||
|
expect(wrapper.find("div > div").length).toEqual(1)
|
||||||
|
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("passes defaultModelExpandDepth to ModelComponent", function(){
|
||||||
|
// When
|
||||||
|
let expandDepth = 0
|
||||||
|
props.isExecute = false
|
||||||
|
props.getConfigs = () => ({
|
||||||
|
defaultModelRendering: "model",
|
||||||
|
defaultModelExpandDepth: expandDepth
|
||||||
|
})
|
||||||
|
let wrapper = shallow(<ModelExample {...props}/>)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(expandDepth)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
51
test/components/models.js
Normal file
51
test/components/models.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import Models from "components/models"
|
||||||
|
import ModelCollpase from "components/model-collapse"
|
||||||
|
import ModelComponent from "components/model-wrapper"
|
||||||
|
|
||||||
|
describe("<Models/>", function(){
|
||||||
|
// Given
|
||||||
|
let components = {
|
||||||
|
Collapse: ModelCollpase,
|
||||||
|
ModelWrapper: ModelComponent
|
||||||
|
}
|
||||||
|
let props = {
|
||||||
|
getComponent: (c) => {
|
||||||
|
return components[c]
|
||||||
|
},
|
||||||
|
specSelectors: {
|
||||||
|
definitions: function() {
|
||||||
|
return fromJS({
|
||||||
|
def1: {},
|
||||||
|
def2: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layoutSelectors: {
|
||||||
|
isShown: createSpy()
|
||||||
|
},
|
||||||
|
layoutActions: {},
|
||||||
|
getConfigs: () => ({
|
||||||
|
docExpansion: "list",
|
||||||
|
defaultModelExpandDepth: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it("passes defaultModelExpandDepth to ModelWrapper", function(){
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<Models {...props}/>)
|
||||||
|
|
||||||
|
// Then should render tabs
|
||||||
|
expect(wrapper.find("ModelCollapse").length).toEqual(1)
|
||||||
|
expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0)
|
||||||
|
wrapper.find("ModelComponent").forEach((modelWrapper) => {
|
||||||
|
expect(modelWrapper.props().expandDepth).toBe(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
49
test/components/primitive-model.js
Normal file
49
test/components/primitive-model.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import PrimitiveModel from "components/primitive-model"
|
||||||
|
|
||||||
|
describe("<PrimitiveModel/>", function() {
|
||||||
|
describe("Model name", function() {
|
||||||
|
const dummyComponent = () => null
|
||||||
|
const components = {
|
||||||
|
Markdown: dummyComponent,
|
||||||
|
EnumModel: dummyComponent
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
getComponent: c => components[c],
|
||||||
|
name: "Name from props",
|
||||||
|
depth: 1,
|
||||||
|
schema: fromJS({
|
||||||
|
type: "string",
|
||||||
|
title: "Custom model title"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it("renders the schema's title", function() {
|
||||||
|
// When
|
||||||
|
const wrapper = shallow(<PrimitiveModel {...props}/>)
|
||||||
|
const modelTitleEl = wrapper.find("span.model-title")
|
||||||
|
expect(modelTitleEl.length).toEqual(1)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect( modelTitleEl.text() ).toEqual( "Custom model title" )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("falls back to the passed-in `name` prop for the title", function() {
|
||||||
|
// When
|
||||||
|
props.schema = fromJS({
|
||||||
|
type: "string"
|
||||||
|
})
|
||||||
|
const wrapper = shallow(<PrimitiveModel {...props}/>)
|
||||||
|
const modelTitleEl = wrapper.find("span.model-title")
|
||||||
|
expect(modelTitleEl.length).toEqual(1)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect( modelTitleEl.text() ).toEqual( "Name from props" )
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
} )
|
||||||
58
test/components/response.js
Normal file
58
test/components/response.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import Response from "components/response"
|
||||||
|
import ModelExample from "components/model-example"
|
||||||
|
import { inferSchema } from "corePlugins/samples/fn"
|
||||||
|
|
||||||
|
describe("<Response />", function() {
|
||||||
|
const dummyComponent = () => null
|
||||||
|
const components = {
|
||||||
|
headers: dummyComponent,
|
||||||
|
highlightCode: dummyComponent,
|
||||||
|
modelExample: ModelExample,
|
||||||
|
Markdown: dummyComponent,
|
||||||
|
operationLink: dummyComponent,
|
||||||
|
contentType: dummyComponent
|
||||||
|
}
|
||||||
|
const props = {
|
||||||
|
getComponent: c => components[c],
|
||||||
|
specSelectors: {
|
||||||
|
isOAS3() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
inferSchema
|
||||||
|
},
|
||||||
|
contentType: "application/json",
|
||||||
|
className: "for-test",
|
||||||
|
response: fromJS({
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
// Note reverse order: c, b, a
|
||||||
|
"c": {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
code: "200"
|
||||||
|
}
|
||||||
|
|
||||||
|
it("renders the model-example schema properties in order", function() {
|
||||||
|
const wrapper = shallow(<Response {...props}/>)
|
||||||
|
const renderedModelExample = wrapper.find(ModelExample)
|
||||||
|
expect(renderedModelExample.length).toEqual(1)
|
||||||
|
|
||||||
|
// Assert the schema's properties have maintained their order
|
||||||
|
const modelExampleSchemaProperties = renderedModelExample.props().schema.toJS().properties
|
||||||
|
expect( Object.keys(modelExampleSchemaProperties) ).toEqual(["c", "b", "a"])
|
||||||
|
})
|
||||||
|
})
|
||||||
39
test/core/oauth2-authorize.js
Normal file
39
test/core/oauth2-authorize.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* eslint-env mocha */
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import win from "core/window"
|
||||||
|
import oauth2Authorize from "core/oauth2-authorize"
|
||||||
|
|
||||||
|
describe("oauth2", function () {
|
||||||
|
|
||||||
|
let mockSchema = {
|
||||||
|
flow: "accessCode",
|
||||||
|
authorizationUrl: "https://testAuthorizationUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
let authConfig = {
|
||||||
|
auth: { schema: { get: (key)=> mockSchema[key] } },
|
||||||
|
authActions: {},
|
||||||
|
errActions: {},
|
||||||
|
configs: { oauth2RedirectUrl: "" },
|
||||||
|
authConfigs: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("authorize redirect", function () {
|
||||||
|
|
||||||
|
it("should build authorize url", function() {
|
||||||
|
win.open = createSpy()
|
||||||
|
oauth2Authorize(authConfig)
|
||||||
|
expect(win.open.calls.length).toEqual(1)
|
||||||
|
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&state=")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should append query paramters to authorizeUrl with query parameters", function() {
|
||||||
|
win.open = createSpy()
|
||||||
|
mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1"
|
||||||
|
oauth2Authorize(authConfig)
|
||||||
|
expect(win.open.calls.length).toEqual(1)
|
||||||
|
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&state=")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -93,6 +93,55 @@ describe("spec plugin - actions", function(){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should pass requestInterceptor/responseInterceptor to fn.execute", function(){
|
||||||
|
// Given
|
||||||
|
let configs = {
|
||||||
|
requestInterceptor: createSpy(),
|
||||||
|
responseInterceptor: createSpy()
|
||||||
|
}
|
||||||
|
const system = {
|
||||||
|
fn: {
|
||||||
|
buildRequest: createSpy(),
|
||||||
|
execute: createSpy().andReturn(Promise.resolve())
|
||||||
|
},
|
||||||
|
specActions: {
|
||||||
|
executeRequest: createSpy(),
|
||||||
|
setMutatedRequest: createSpy(),
|
||||||
|
setRequest: createSpy()
|
||||||
|
},
|
||||||
|
specSelectors: {
|
||||||
|
spec: () => fromJS({}),
|
||||||
|
parameterValues: () => fromJS({}),
|
||||||
|
contentTypeValues: () => fromJS({}),
|
||||||
|
url: () => fromJS({}),
|
||||||
|
isOAS3: () => false
|
||||||
|
},
|
||||||
|
getConfigs: () => configs
|
||||||
|
}
|
||||||
|
// When
|
||||||
|
let executeFn = executeRequest({
|
||||||
|
pathName: "/one",
|
||||||
|
method: "GET",
|
||||||
|
operation: fromJS({operationId: "getOne"})
|
||||||
|
})
|
||||||
|
let res = executeFn(system)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(system.fn.execute.calls.length).toEqual(1)
|
||||||
|
expect(system.fn.execute.calls[0].arguments[0]).toIncludeKey("requestInterceptor")
|
||||||
|
expect(system.fn.execute.calls[0].arguments[0]).toInclude({
|
||||||
|
responseInterceptor: configs.responseInterceptor
|
||||||
|
})
|
||||||
|
expect(system.specActions.setMutatedRequest.calls.length).toEqual(0)
|
||||||
|
expect(system.specActions.setRequest.calls.length).toEqual(1)
|
||||||
|
|
||||||
|
|
||||||
|
let wrappedRequestInterceptor = system.fn.execute.calls[0].arguments[0].requestInterceptor
|
||||||
|
wrappedRequestInterceptor(system.fn.execute.calls[0].arguments[0])
|
||||||
|
expect(configs.requestInterceptor.calls.length).toEqual(1)
|
||||||
|
expect(system.specActions.setMutatedRequest.calls.length).toEqual(1)
|
||||||
|
expect(system.specActions.setRequest.calls.length).toEqual(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
xit("should call specActions.setResponse, when fn.execute resolves", function(){
|
xit("should call specActions.setResponse, when fn.execute resolves", function(){
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/one": {
|
"/one": {
|
||||||
get: {
|
get: {
|
||||||
parameters: [
|
parameters: [
|
||||||
{ name: "one", value: 1},
|
{ name: "one", in: "query", value: 1},
|
||||||
{ name: "two", value: "duos"}
|
{ name: "two", in: "query", value: "duos"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,8 +43,8 @@ describe("spec plugin - selectors", function(){
|
|||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(paramValues.toJS()).toEqual({
|
expect(paramValues.toJS()).toEqual({
|
||||||
one: 1,
|
"query.one": 1,
|
||||||
two: "duos"
|
"query.two": "duos"
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
import expect from "expect"
|
import expect from "expect"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS, OrderedMap } from "immutable"
|
||||||
import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils"
|
import {
|
||||||
|
mapToList,
|
||||||
|
validateMinLength,
|
||||||
|
validateMaxLength,
|
||||||
|
validateDateTime,
|
||||||
|
validateGuid,
|
||||||
|
validateNumber,
|
||||||
|
validateInteger,
|
||||||
|
validateParam,
|
||||||
|
validateFile,
|
||||||
|
validateMaximum,
|
||||||
|
validateMinimum,
|
||||||
|
fromJSOrdered,
|
||||||
|
getAcceptControllingResponse,
|
||||||
|
createDeepLinkPath,
|
||||||
|
escapeDeepLinkPath
|
||||||
|
} from "core/utils"
|
||||||
import win from "core/window"
|
import win from "core/window"
|
||||||
|
|
||||||
describe("utils", function() {
|
describe("utils", function() {
|
||||||
@@ -72,6 +88,36 @@ describe("utils", function() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("validateMaximum", function() {
|
||||||
|
let errorMessage = "Value must be less than Maximum"
|
||||||
|
|
||||||
|
it("doesn't return for valid input", function() {
|
||||||
|
expect(validateMaximum(9, 10)).toBeFalsy()
|
||||||
|
expect(validateMaximum(19, 20)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input", function() {
|
||||||
|
expect(validateMaximum(1, 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMaximum(10, 9)).toEqual(errorMessage)
|
||||||
|
expect(validateMaximum(20, 19)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMinimum", function() {
|
||||||
|
let errorMessage = "Value must be greater than Minimum"
|
||||||
|
|
||||||
|
it("doesn't return for valid input", function() {
|
||||||
|
expect(validateMinimum(2, 1)).toBeFalsy()
|
||||||
|
expect(validateMinimum(20, 10)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input", function() {
|
||||||
|
expect(validateMinimum(-1, 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMinimum(1, 2)).toEqual(errorMessage)
|
||||||
|
expect(validateMinimum(10, 20)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("validateNumber", function() {
|
describe("validateNumber", function() {
|
||||||
let errorMessage = "Value must be a number"
|
let errorMessage = "Value must be a number"
|
||||||
|
|
||||||
@@ -171,6 +217,62 @@ describe("utils", function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("validateDateTime", function() {
|
||||||
|
let errorMessage = "Value must be a DateTime"
|
||||||
|
|
||||||
|
it("doesn't return for valid dates", function() {
|
||||||
|
expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateDateTime(null)).toEqual(errorMessage)
|
||||||
|
expect(validateDateTime("string")).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateGuid", function() {
|
||||||
|
let errorMessage = "Value must be a Guid"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
|
||||||
|
expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateGuid(1)).toEqual(errorMessage)
|
||||||
|
expect(validateGuid("string")).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMaxLength", function() {
|
||||||
|
let errorMessage = "Value must be less than MaxLength"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateMaxLength("a", 1)).toBeFalsy()
|
||||||
|
expect(validateMaxLength("abc", 5)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateMaxLength("abc", 0)).toEqual(errorMessage)
|
||||||
|
expect(validateMaxLength("abc", 1)).toEqual(errorMessage)
|
||||||
|
expect(validateMaxLength("abc", 2)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("validateMinLength", function() {
|
||||||
|
let errorMessage = "Value must be greater than MinLength"
|
||||||
|
|
||||||
|
it("doesn't return for valid guid", function() {
|
||||||
|
expect(validateMinLength("a", 1)).toBeFalsy()
|
||||||
|
expect(validateMinLength("abc", 2)).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a message for invalid input'", function() {
|
||||||
|
expect(validateMinLength("abc", 5)).toEqual(errorMessage)
|
||||||
|
expect(validateMinLength("abc", 8)).toEqual(errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("validateParam", function() {
|
describe("validateParam", function() {
|
||||||
let param = null
|
let param = null
|
||||||
let result = null
|
let result = null
|
||||||
@@ -204,6 +306,50 @@ describe("utils", function() {
|
|||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid string with min and max length
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 50,
|
||||||
|
minLength: 1
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates required strings with min and max length", function() {
|
||||||
|
// invalid string with max length
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 5
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be less than MaxLength"] )
|
||||||
|
|
||||||
|
// invalid string with max length 0
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
maxLength: 0
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be less than MaxLength"] )
|
||||||
|
|
||||||
|
|
||||||
|
// invalid string with min length
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string",
|
||||||
|
minLength: 50
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be greater than MinLength"] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional strings", function() {
|
it("validates optional strings", function() {
|
||||||
@@ -458,14 +604,47 @@ describe("utils", function() {
|
|||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
// valid number
|
// valid number with min and max
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: 10
|
value: 10,
|
||||||
|
minimum: 5,
|
||||||
|
maximum: 99
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid negative number with min and max
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: -10,
|
||||||
|
minimum: -50,
|
||||||
|
maximum: -5
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// invalid number with maximum:0
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: 1,
|
||||||
|
maximum: 0
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be less than Maximum"] )
|
||||||
|
|
||||||
|
// invalid number with minimum:0
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: -10,
|
||||||
|
minimum: 0
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be greater than Minimum"] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional numbers", function() {
|
it("validates optional numbers", function() {
|
||||||
@@ -582,4 +761,151 @@ describe("utils", function() {
|
|||||||
expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
|
expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("getAcceptControllingResponse", () => {
|
||||||
|
it("should return the first 2xx response with a media type", () => {
|
||||||
|
const responses = fromJSOrdered({
|
||||||
|
"200": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("200"))
|
||||||
|
})
|
||||||
|
it("should skip 2xx responses without defined media types", () => {
|
||||||
|
const responses = fromJSOrdered({
|
||||||
|
"200": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("201"))
|
||||||
|
})
|
||||||
|
it("should default to the `default` response if it has defined media types", () => {
|
||||||
|
const responses = fromJSOrdered({
|
||||||
|
"200": {
|
||||||
|
description: "quite empty"
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
description: "quite empty"
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("default"))
|
||||||
|
})
|
||||||
|
it("should return null if there are no suitable controlling responses", () => {
|
||||||
|
const responses = fromJSOrdered({
|
||||||
|
"200": {
|
||||||
|
description: "quite empty"
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
description: "quite empty"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
description: "also empty.."
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toBe(null)
|
||||||
|
})
|
||||||
|
it("should return null if an empty OrderedMap is passed", () => {
|
||||||
|
const responses = fromJSOrdered()
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toBe(null)
|
||||||
|
})
|
||||||
|
it("should return null if anything except an OrderedMap is passed", () => {
|
||||||
|
const responses = {}
|
||||||
|
|
||||||
|
expect(getAcceptControllingResponse(responses)).toBe(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("createDeepLinkPath", function() {
|
||||||
|
it("creates a deep link path replacing spaces with underscores", function() {
|
||||||
|
const result = createDeepLinkPath("tag id with spaces")
|
||||||
|
expect(result).toEqual("tag_id_with_spaces")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("trims input when creating a deep link path", function() {
|
||||||
|
let result = createDeepLinkPath(" spaces before and after ")
|
||||||
|
expect(result).toEqual("spaces_before_and_after")
|
||||||
|
|
||||||
|
result = createDeepLinkPath(" ")
|
||||||
|
expect(result).toEqual("")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("creates a deep link path with special characters", function() {
|
||||||
|
const result = createDeepLinkPath("!@#$%^&*(){}[]")
|
||||||
|
expect(result).toEqual("!@#$%^&*(){}[]")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns an empty string for invalid input", function() {
|
||||||
|
expect( createDeepLinkPath(null) ).toEqual("")
|
||||||
|
expect( createDeepLinkPath(undefined) ).toEqual("")
|
||||||
|
expect( createDeepLinkPath(1) ).toEqual("")
|
||||||
|
expect( createDeepLinkPath([]) ).toEqual("")
|
||||||
|
expect( createDeepLinkPath({}) ).toEqual("")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("escapeDeepLinkPath", function() {
|
||||||
|
it("creates and escapes a deep link path", function() {
|
||||||
|
const result = escapeDeepLinkPath("tag id with spaces?")
|
||||||
|
expect(result).toEqual("tag_id_with_spaces\\?")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("escapes a deep link path that starts with a number", function() {
|
||||||
|
const result = escapeDeepLinkPath("123")
|
||||||
|
expect(result).toEqual("\\31 23")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("escapes a deep link path with a class selector", function() {
|
||||||
|
const result = escapeDeepLinkPath("hello.world")
|
||||||
|
expect(result).toEqual("hello\\.world")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("escapes a deep link path with an id selector", function() {
|
||||||
|
const result = escapeDeepLinkPath("hello#world")
|
||||||
|
expect(result).toEqual("hello\\#world")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user