Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73d2e90e12 | ||
|
|
875caab173 | ||
|
|
ef95d6e00c | ||
|
|
21b0037529 | ||
|
|
3f06bb50fb | ||
|
|
f7001f8011 | ||
|
|
742f4bcfb3 | ||
|
|
bf21ebbc0c | ||
|
|
9d02a7d8ad | ||
|
|
a86fcf312a | ||
|
|
815dbe0b5d | ||
|
|
b78ec5bd9d | ||
|
|
8e295c23a4 | ||
|
|
634615346d | ||
|
|
98d6128375 | ||
|
|
24faa4690f | ||
|
|
7c33ae9c49 | ||
|
|
bf77474a11 | ||
|
|
8416b043ea | ||
|
|
0eb591b78a | ||
|
|
f53f92351e | ||
|
|
3fa3e2d89d | ||
|
|
a2015ee08b | ||
|
|
8fd919eede | ||
|
|
f1cdb6a032 | ||
|
|
a03c12786a | ||
|
|
a51bf1ea3e | ||
|
|
690e274e07 | ||
|
|
a2fee7ed58 | ||
|
|
90157c1a40 | ||
|
|
5ea2150ae7 | ||
|
|
d91e4e84b8 | ||
|
|
798cc88968 | ||
|
|
1214477117 | ||
|
|
bacea7af8a | ||
|
|
43304aa80a | ||
|
|
cdbd120589 | ||
|
|
37001b38bb | ||
|
|
32ab8b3ce8 | ||
|
|
6b3aba697e | ||
|
|
aa22756641 | ||
|
|
16bf8fb3be | ||
|
|
bf5acc1f40 | ||
|
|
c1007a287b | ||
|
|
c8480a827a | ||
|
|
55fdeeb810 | ||
|
|
9e3a801750 | ||
|
|
9155eb946e | ||
|
|
66e9bd735a | ||
|
|
ae849c31ea | ||
|
|
1a95b9e9c9 | ||
|
|
073b1df730 | ||
|
|
11c586309f | ||
|
|
a37d637061 | ||
|
|
75747424cf | ||
|
|
8055129dd2 |
@@ -6,6 +6,7 @@
|
||||
],
|
||||
"plugins": [
|
||||
"transform-runtime",
|
||||
"babel-plugin-transform-es2015-constants",
|
||||
[
|
||||
"module-alias",
|
||||
[
|
||||
@@ -17,6 +18,10 @@
|
||||
"expose": "components",
|
||||
"src": "src/core/components"
|
||||
},
|
||||
{
|
||||
"expose": "containers",
|
||||
"src": "src/core/containers"
|
||||
},
|
||||
{
|
||||
"expose": "core",
|
||||
"src": "src/core"
|
||||
@@ -36,10 +41,6 @@
|
||||
{
|
||||
"expose": "less",
|
||||
"src": "src/less"
|
||||
},
|
||||
{
|
||||
"expose": "base",
|
||||
"src": "npm:getbase/src/less/base"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -13,11 +13,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
|
||||
"plugins": [
|
||||
"react",
|
||||
"mocha"
|
||||
"mocha",
|
||||
"import"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
@@ -34,6 +38,7 @@
|
||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||
"react/jsx-no-bind": 1,
|
||||
"react/display-name": 0,
|
||||
"mocha/no-exclusive-tests": "error"
|
||||
"mocha/no-exclusive-tests": "error",
|
||||
"import/no-extraneous-dependencies": [2]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report an issue you're experiencing
|
||||
|
||||
---
|
||||
|
||||
<!---
|
||||
Thanks for filing a bug report! 😄
|
||||
|
||||
Before you submit, please read the following:
|
||||
|
||||
If you're here to report a security issue, please STOP writing an issue and
|
||||
contact us at security@swagger.io instead!
|
||||
|
||||
Search open/closed issues before submitting!
|
||||
|
||||
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try
|
||||
to offer support here for your use case, but we can't offer help with projects
|
||||
that use Swagger-UI indirectly, like Springfox or swagger-node.
|
||||
|
||||
Likewise, we can't accept bugs in the Swagger/OpenAPI specifications
|
||||
themselves, or anything that violates the specifications.
|
||||
-->
|
||||
|
||||
### Q&A (please complete the following information)
|
||||
- OS: [e.g. macOS]
|
||||
- Browser: [e.g. chrome, safari]
|
||||
- Version: [e.g. 22]
|
||||
- Method of installation: [e.g. npm, dist assets]
|
||||
- Swagger-UI version: [e.g. 3.10.0]
|
||||
- Swagger/OpenAPI version: [e.g. Swagger 2.0, OpenAPI 3.0]
|
||||
|
||||
### Content & configuration
|
||||
<!--
|
||||
Provide us with a way to see what you're seeing,
|
||||
so that we can fix your issue.
|
||||
-->
|
||||
|
||||
Example Swagger/OpenAPI definition:
|
||||
```yaml
|
||||
# your YAML here
|
||||
```
|
||||
|
||||
Swagger-UI configuration options:
|
||||
```js
|
||||
SwaggerUI({
|
||||
// your config options here
|
||||
})
|
||||
```
|
||||
|
||||
```
|
||||
?yourQueryStringConfig
|
||||
```
|
||||
|
||||
### Describe the bug you're encountering
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
### To reproduce...
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
### Expected behavior
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
### Screenshots
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
### Additional context or thoughts
|
||||
<!-- Add any other context about the problem here. -->
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an new feature or enhancement for this project
|
||||
|
||||
---
|
||||
|
||||
### Q&A (please complete the following information)
|
||||
- OS: [e.g. macOS]
|
||||
- Browser: [e.g. chrome, safari]
|
||||
- Version: [e.g. 22]
|
||||
- Method of installation: [e.g. npm, dist assets]
|
||||
- Swagger-UI version: [e.g. 3.10.0]
|
||||
- Swagger/OpenAPI version: [e.g. Swagger 2.0, OpenAPI 3.0]
|
||||
|
||||
### Content & configuration
|
||||
|
||||
Swagger/OpenAPI definition:
|
||||
```yaml
|
||||
# your YAML here
|
||||
```
|
||||
|
||||
Swagger-UI configuration options:
|
||||
```js
|
||||
SwaggerUI({
|
||||
// your config options here
|
||||
})
|
||||
```
|
||||
|
||||
```
|
||||
?yourQueryStringConfig
|
||||
```
|
||||
|
||||
|
||||
### Is your feature request related to a problem?
|
||||
<!--
|
||||
Please provide a clear and concise description of what the problem is.
|
||||
"I'm always frustrated when..."
|
||||
-->
|
||||
|
||||
### Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
### Describe alternatives you've considered
|
||||
<!--
|
||||
A clear and concise description of any alternative solutions or features
|
||||
you've considered.
|
||||
-->
|
||||
|
||||
### Additional context
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: Support
|
||||
about: Ask a question or request help with your implementation.
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
We can only offer support for Swagger-UI itself.
|
||||
|
||||
If you're having a problem with a library that uses Swagger-UI
|
||||
(for example, Springfox or swagger-node), please open an issue
|
||||
in that project's repository instead.
|
||||
-->
|
||||
|
||||
### Q&A (please complete the following information)
|
||||
- OS: [e.g. macOS]
|
||||
- Browser: [e.g. chrome, safari]
|
||||
- Version: [e.g. 22]
|
||||
- Method of installation: [e.g. npm, dist assets]
|
||||
- Swagger-UI version: [e.g. 3.10.0]
|
||||
- Swagger/OpenAPI version: [e.g. Swagger 2.0, OpenAPI 3.0]
|
||||
|
||||
### Content & configuration
|
||||
<!-- Provide us with a way to see what you're seeing, so that we can help. -->
|
||||
|
||||
Swagger/OpenAPI definition:
|
||||
```yaml
|
||||
# your YAML here
|
||||
```
|
||||
|
||||
Swagger-UI configuration options:
|
||||
```js
|
||||
SwaggerUI({
|
||||
// your config options here
|
||||
})
|
||||
```
|
||||
|
||||
```
|
||||
?yourQueryStringConfig
|
||||
```
|
||||
|
||||
### Screenshots
|
||||
<!-- If applicable, add screenshots to help give context to your problem. -->
|
||||
|
||||
### How can we help?
|
||||
<!-- Your question or problem goes here! -->
|
||||
@@ -1,70 +0,0 @@
|
||||
<!---
|
||||
Thanks for filing an issue 😄 ! Before you submit, please read the following:
|
||||
|
||||
If you're here to report a security issue, please STOP writing an issue and contact us
|
||||
at security@swagger.io instead!
|
||||
|
||||
Search open/closed issues before submitting since someone might have asked the same thing before!
|
||||
|
||||
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try to offer support
|
||||
here for your use case, but we can't offer help with projects that use Swagger-UI indirectly,
|
||||
like Springfox or swagger-node.
|
||||
|
||||
Likewise, we can't accept features or bugs in the Swagger/OpenAPI specifications themselves,
|
||||
or anything that violates the specifications.
|
||||
|
||||
-->
|
||||
|
||||
<!--- 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/usage/version-detection.md
|
||||
--->
|
||||
|
||||
|
||||
| Q | A
|
||||
| ------------------------------- | -------
|
||||
| Bug or feature request? |
|
||||
| Which Swagger/OpenAPI version? |
|
||||
| Which Swagger-UI version? |
|
||||
| How did you install Swagger-UI? |
|
||||
| Which browser & version? |
|
||||
| Which operating system? |
|
||||
|
||||
|
||||
### Demonstration API definition
|
||||
<!--- If you're describing a bug, please provide an API definition that reproduces your problem -->
|
||||
<!--- If you have link to a demo repo please link that! -->
|
||||
|
||||
<!--- If your spec is large, please put it into a Gist (https://gist.github.com) instead of pasting it here. -->
|
||||
|
||||
```yaml
|
||||
your: "API definition goes here"
|
||||
```
|
||||
|
||||
### Configuration (browser query string, constructor, config.yaml)
|
||||
<!--- If describing a bug, tell us what your configuration looks like -->
|
||||
|
||||
```js
|
||||
{
|
||||
"your": { "constructorConfig": "here" }
|
||||
}
|
||||
```
|
||||
|
||||
`?yourQueryStringConfig=here`
|
||||
|
||||
### Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
### Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
### Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
### Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
@@ -5,7 +5,6 @@ node_modules
|
||||
.nyc_output
|
||||
npm-debug.log*
|
||||
.eslintcache
|
||||
package-lock.json
|
||||
*.iml
|
||||
selenium-debug.log
|
||||
test/e2e/db.json
|
||||
|
||||
+5
-1
@@ -15,6 +15,8 @@ before_deploy:
|
||||
- npm run build
|
||||
env:
|
||||
- DOCKER_IMAGE_NAME=swaggerapi/swagger-ui
|
||||
script:
|
||||
- npm test
|
||||
deploy:
|
||||
- provider: npm
|
||||
email: apiteam@swagger.io
|
||||
@@ -37,7 +39,7 @@ after_success:
|
||||
docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD;
|
||||
|
||||
if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
DOCKER_IMAGE_TAG=$TRAVIS_TAG;
|
||||
DOCKER_IMAGE_TAG=${TRAVIS_TAG#?};
|
||||
else
|
||||
DOCKER_IMAGE_TAG=unstable;
|
||||
fi;
|
||||
@@ -52,3 +54,5 @@ after_success:
|
||||
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
|
||||
fi;
|
||||
fi;
|
||||
- npm run build-bundle
|
||||
- bundlesize
|
||||
+1
-1
@@ -4,7 +4,7 @@ LABEL maintainer="fehguy"
|
||||
|
||||
ENV VERSION "v2.2.10"
|
||||
ENV FOLDER "swagger-ui-2.2.10"
|
||||
ENV API_URL "http://petstore.swagger.io/v2/swagger.json"
|
||||
ENV API_URL "https://petstore.swagger.io/v2/swagger.json"
|
||||
ENV API_URLS ""
|
||||
ENV API_KEY "**None**"
|
||||
ENV OAUTH_CLIENT_ID "**None**"
|
||||
|
||||
@@ -2,27 +2,25 @@
|
||||
|
||||
[](http://badge.fury.io/js/swagger-ui)
|
||||
|
||||
## New!
|
||||
|
||||
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
|
||||
|
||||
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first issue](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22) label.
|
||||
|
||||
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.
|
||||
**🕰️ Looking for the older version of Swagger UI?** Refer to the [*2.x* branch](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||
|
||||
|
||||
This repository publishes to two different NPM modules:
|
||||
|
||||
* [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) 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.
|
||||
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is a traditional npm module intended for use in single-page applications that are capable of resolving dependencies (via Webpack, Browserify, etc).
|
||||
* [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 single-page application that can't resolve npm module dependencies.
|
||||
|
||||
We strongly suggest that you use `swagger-ui` instead of `swagger-ui-dist` if you're building a single-page application, since `swagger-ui-dist` is significantly larger.
|
||||
|
||||
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||
|
||||
## Compatibility
|
||||
The OpenAPI Specification has undergone 5 revisions since initial creation in 2010. Compatibility between swagger-ui and the OpenAPI Specification is as follows:
|
||||
The OpenAPI Specification has undergone 5 revisions since initial creation in 2010. Compatibility between Swagger UI and the OpenAPI Specification is as follows:
|
||||
|
||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||
------------------ | ------------ | -------------------------- | -----
|
||||
3.14.0 | 2018-04-27 | 2.0, 3.0 | [tag v3.14.0](https://github.com/swagger-api/swagger-ui/tree/v3.14.0)
|
||||
3.17.2 | 2018-06-16 | 2.0, 3.0 | [tag v3.17.2](https://github.com/swagger-api/swagger-ui/tree/v3.17.2)
|
||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
||||
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
||||
@@ -76,7 +74,7 @@ Please disclose any security-related issues or vulnerabilities by emailing [secu
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2017 SmartBear Software
|
||||
Copyright 2018 SmartBear Software
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Swagger UI</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
@@ -43,7 +42,7 @@
|
||||
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
|
||||
// Build a system
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
|
||||
Vendored
+1
-2
@@ -4,7 +4,6 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
@@ -41,7 +40,7 @@
|
||||
|
||||
// Build a system
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
|
||||
Vendored
+42
-31
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+5
-4
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-2
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+4
-4
@@ -38,10 +38,10 @@ fi
|
||||
if [[ -f $SWAGGER_JSON ]]; then
|
||||
cp -s $SWAGGER_JSON $NGINX_ROOT
|
||||
REL_PATH="./$(basename $SWAGGER_JSON)"
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
|
||||
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
|
||||
else
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$API_URL|g" $INDEX_FILE
|
||||
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$API_URL|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|$API_URL|g" $INDEX_FILE
|
||||
fi
|
||||
|
||||
@@ -55,11 +55,11 @@ fi
|
||||
|
||||
# replace `url` with `urls` option if API_URLS is set
|
||||
if [[ -n "$API_URLS" ]]; then
|
||||
sed -i "s|url: .*,|urls: $API_URLS,|g" $INDEX_FILE
|
||||
sed -i "s|^\(\s*\)url: .*,|\1urls: $API_URLS,|g" $INDEX_FILE
|
||||
fi
|
||||
|
||||
# replace the PORT that nginx listens on if PORT is supplied
|
||||
if [[ -n "${PORT}" ]]; then
|
||||
if [[ -n "${PORT}" ]]; then
|
||||
sed -i "s|8080|${PORT}|g" /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ const OperationsLayoutPlugin = () => {
|
||||
// Provide the plugin to Swagger-UI, and select OperationsLayout
|
||||
// as the layout for Swagger-UI
|
||||
SwaggerUI({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
plugins: [ OperationsLayoutPlugin ],
|
||||
layout: "OperationsLayout"
|
||||
})
|
||||
@@ -85,7 +85,7 @@ const AugmentingLayoutPlugin = () => {
|
||||
// Provide the plugin to Swagger-UI, and select AugmentingLayout
|
||||
// as the layout for Swagger-UI
|
||||
SwaggerUI({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
plugins: [ AugmentingLayoutPlugin ],
|
||||
layout: "AugmentingLayout"
|
||||
})
|
||||
|
||||
@@ -17,7 +17,7 @@ Script name | Description
|
||||
--- | ---
|
||||
`build` | Build a new set of JS and CSS assets, and output them to `/dist`.
|
||||
`build-bundle` | Build `swagger-ui-bundle.js` only.
|
||||
`build-core` | Build `swagger-ui.(js|css)` only.
|
||||
`build-core` | Build `swagger-ui.(js\|css)` only.
|
||||
`build-standalone` | Build `swagger-ui-standalone-preset.js` only.
|
||||
|
||||
### Testing
|
||||
|
||||
@@ -30,7 +30,7 @@ Parameter Name | Description
|
||||
`domNode` | `Element`, **REQUIRED** if `dom_id` is not provided. The HTML DOM element inside which SwaggerUi will put the user interface for swagger. Overrides `dom_id`.
|
||||
`spec` | `Object={}`. A JS object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
|
||||
`url` | `String`. The url pointing to API definition (normally `swagger.json` or `swagger.yaml`). Will be ignored if `urls` or `spec` is used.
|
||||
`urls` | `String`. An array of API definition objects (`{url: "<url>", name: "<name>"}`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
|
||||
`urls` | `Array`. An array of API definition objects (`[{url: "<url1>", name: "<name1>"},{url: "<url2>", name: "<name2>"}]`) used by Topbar plugin. When used and Topbar plugin is enabled, the `url` parameter will not be parsed. Names and URLs must be unique among all items in this array, since they're used as identifiers.
|
||||
`urls.primaryName` | `String`. When using `urls`, you can use this subparameter. If the value matches the name of a spec provided in `urls`, that spec will be displayed when Swagger-UI loads, instead of defaulting to the first spec in `urls`.
|
||||
|
||||
##### Plugin system
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ You can verify CORS support with one of three techniques:
|
||||
- Curl your API and inspect the headers. For instance:
|
||||
|
||||
```bash
|
||||
$ curl -I "http://petstore.swagger.io/v2/swagger.json"
|
||||
$ curl -I "https://petstore.swagger.io/v2/swagger.json"
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sat, 31 Jan 2015 23:05:44 GMT
|
||||
Access-Control-Allow-Origin: *
|
||||
|
||||
@@ -44,7 +44,7 @@ you could do something like this:
|
||||
var SwaggerUIBundle = require('swagger-ui-dist').SwaggerUIBundle
|
||||
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
|
||||
@@ -3,9 +3,9 @@ You can configure OAuth2 authorization by calling the `initOAuth` method.
|
||||
|
||||
Config Name | Description
|
||||
--- | ---
|
||||
client_id | Default clientId. MUST be a string
|
||||
client_secret | Default clientSecret. MUST be a string
|
||||
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl` . MUST be a string
|
||||
clientId | Default clientId. MUST be a string
|
||||
clientSecret | **🚨 Never use this parameter in your production environemnt. It exposes cruicial security information. This feature is intended for dev/test environments only. 🚨** <br>Default clientSecret. MUST be a string
|
||||
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl`. MUST be a string
|
||||
appName | application name, displayed in authorization popup. MUST be a string
|
||||
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
|
||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||
|
||||
+21
-13
@@ -1,10 +1,11 @@
|
||||
var path = require("path")
|
||||
|
||||
var webpack = require('webpack')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
var deepExtend = require('deep-extend')
|
||||
const {gitDescribeSync} = require('git-describe')
|
||||
var webpack = require("webpack")
|
||||
var ExtractTextPlugin = require("extract-text-webpack-plugin")
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin")
|
||||
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
|
||||
var deepExtend = require("deep-extend")
|
||||
const {gitDescribeSync} = require("git-describe")
|
||||
const os = require("os")
|
||||
|
||||
var pkg = require("./package.json")
|
||||
@@ -28,7 +29,10 @@ var commonRules = [
|
||||
retainLines: true
|
||||
}
|
||||
}],
|
||||
include: [ path.join(__dirname, "src") ]
|
||||
include: [
|
||||
path.join(__dirname, "src"),
|
||||
path.join(__dirname, "node_modules", "object-assign-deep"),
|
||||
]
|
||||
},
|
||||
{ test: /\.(txt|yaml)(\?.*)?$/,
|
||||
loader: "raw-loader" },
|
||||
@@ -48,6 +52,7 @@ module.exports = function(rules, options) {
|
||||
hot: false,
|
||||
separateStylesheets: true,
|
||||
minimize: false,
|
||||
mangle: false,
|
||||
longTermCaching: false,
|
||||
sourcemaps: false,
|
||||
}, options._special)
|
||||
@@ -61,10 +66,15 @@ module.exports = function(rules, options) {
|
||||
}))
|
||||
}
|
||||
|
||||
if( specialOptions.minimize ) { // production mode
|
||||
if( specialOptions.minimize ) { // production mode
|
||||
|
||||
plugins.push(
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
mangle: specialOptions.mangle,
|
||||
beautify: !specialOptions.mangle,
|
||||
keep_fnames: true
|
||||
},
|
||||
sourceMap: true,
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
@@ -76,8 +86,8 @@ module.exports = function(rules, options) {
|
||||
|
||||
plugins.push( new webpack.NoEmitOnErrorsPlugin())
|
||||
|
||||
} else { // development mode
|
||||
plugins.push(new CopyWebpackPlugin([ { from: 'test/e2e/specs', to: 'test-specs' } ]))
|
||||
} else { // development mode
|
||||
plugins.push(new CopyWebpackPlugin([ { from: "test/e2e/specs", to: "test-specs" } ]))
|
||||
}
|
||||
|
||||
plugins.push(
|
||||
@@ -132,9 +142,7 @@ module.exports = function(rules, options) {
|
||||
"node_modules"
|
||||
],
|
||||
extensions: [".web.js", ".js", ".jsx", ".json", ".less"],
|
||||
alias: {
|
||||
base: "getbase/src/less/base",
|
||||
}
|
||||
alias: {}
|
||||
},
|
||||
|
||||
devtool: specialOptions.sourcemaps ? "nosource-source-map" : false,
|
||||
|
||||
Generated
+20131
File diff suppressed because it is too large
Load Diff
+60
-65
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.14.0",
|
||||
"version": "3.17.2",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -14,7 +14,7 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "npm run build-core && npm run build-bundle && npm run build-standalone",
|
||||
"build": "run-p --aggregate-output build-core build-bundle build-standalone",
|
||||
"build-bundle": "webpack --config webpack-dist-bundle.config.js --colors",
|
||||
"build-core": "webpack --config webpack-dist.config.js --colors",
|
||||
"build-standalone": "webpack --config webpack-dist-standalone.config.js --colors",
|
||||
@@ -24,131 +24,119 @@
|
||||
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/",
|
||||
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv",
|
||||
"deps-size": "webpack -p --config webpack.check.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt",
|
||||
"deps-check": "npm run deps-license && npm run deps-size",
|
||||
"deps-check": "run-s deps-license deps-size",
|
||||
"lint": "eslint --cache --ext '.js,.jsx' src test",
|
||||
"lint-errors": "eslint --cache --quiet --ext '.js,.jsx' src test",
|
||||
"lint-fix": "eslint --cache --ext '.js,.jsx' src test --fix",
|
||||
"test": "npm run lint-errors && npm run just-test-in-node",
|
||||
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
||||
"just-test": "karma start --config karma.conf.js",
|
||||
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package test/xss",
|
||||
"test": "run-s just-test-in-node lint-errors",
|
||||
"test-in-node": "run-s lint-errors just-test-in-node",
|
||||
"just-test-in-node": "mocha --require test/setup.js --recursive --compilers js:babel-core/register --require source-map-support test/core test/components test/bugs test/swagger-ui-dist-package test/xss",
|
||||
"just-check-coverage": "nyc npm run just-test-in-node",
|
||||
"test-e2e": "sleep 3 && nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json",
|
||||
"e2e-initial-render": "nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json --group initial-render",
|
||||
"mock-api": "json-server --watch test/e2e/db.json --port 3204",
|
||||
"hot-e2e-server": "webpack-dev-server --port 3230 --content-base test/e2e/helpers --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress",
|
||||
"e2e": "npm-run-all --parallel -r hot-e2e-server mock-api test-e2e"
|
||||
"e2e": "run-p -r hot-e2e-server mock-api test-e2e",
|
||||
"open-static": "node -e 'require(\"open\")(\"http://localhost:3002\")'",
|
||||
"serve-static": "http-server dist/ -i -a 0.0.0.0 -p 3002",
|
||||
"start": "npm-run-all --parallel serve-static open-static"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^2.0.2",
|
||||
"base64-js": "^1.2.0",
|
||||
"brace": "0.7.0",
|
||||
"classnames": "^2.2.5",
|
||||
"commonmark": "^0.28.1",
|
||||
"core-js": "^2.5.1",
|
||||
"css.escape": "1.5.1",
|
||||
"deep-extend": "0.4.1",
|
||||
"expect": "1.20.2",
|
||||
"getbase": "^2.8.2",
|
||||
"deep-extend": "0.5.1",
|
||||
"dompurify": "^1.0.4",
|
||||
"ieee754": "^1.1.8",
|
||||
"immutable": "^3.x.x",
|
||||
"js-file-download": "^0.4.1",
|
||||
"js-yaml": "^3.5.5",
|
||||
"lodash": "4.17.5",
|
||||
"matcher": "^0.1.2",
|
||||
"memoizee": "0.4.1",
|
||||
"promise-worker": "^1.1.1",
|
||||
"lodash": "^4.17.10",
|
||||
"memoizee": "^0.4.12",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^15.6.2",
|
||||
"react-addons-perf": "^15.4.0",
|
||||
"react-addons-shallow-compare": "0.14.8",
|
||||
"react-addons-test-utils": "^15.6.2",
|
||||
"react-collapse": "^4.0.3",
|
||||
"react-debounce-input": "^3.2.0",
|
||||
"react-dom": "^15.6.2",
|
||||
"react-height": "^2.0.0",
|
||||
"react-hot-loader": "1.3.1",
|
||||
"react-immutable-proptypes": "2.1.0",
|
||||
"react-immutable-pure-component": "^1.1.1",
|
||||
"react-inspector": "^2.3.0",
|
||||
"react-markdown": "^2.5.0",
|
||||
"react-motion": "^0.5.2",
|
||||
"react-object-inspector": "0.2.1",
|
||||
"react-redux": "^4.x.x",
|
||||
"react-split-pane": "0.1.70",
|
||||
"react-split-pane": "^0.1.77",
|
||||
"redux": "^3.x.x",
|
||||
"redux-immutable": "3.0.8",
|
||||
"redux-logger": "*",
|
||||
"remarkable": "^1.7.1",
|
||||
"reselect": "2.5.3",
|
||||
"sanitize-html": "^1.14.1",
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.7.2",
|
||||
"reselect": "^2.5.4",
|
||||
"serialize-error": "^2.1.0",
|
||||
"swagger-client": "^3.8.7",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
"xml": "1.0.1",
|
||||
"xml-but-prettier": "^1.0.1",
|
||||
"yaml-js": "0.2.0",
|
||||
"zenscroll": "4.0.1"
|
||||
"yaml-js": "^0.2.3",
|
||||
"zenscroll": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "7.1.1",
|
||||
"autoprefixer": "^8.4.1",
|
||||
"babel-core": "^6.23.1",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^7.1.0",
|
||||
"babel-plugin-module-alias": "^1.6.0",
|
||||
"babel-plugin-transform-es2015-constants": "^6.1.4",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-es2015-ie": "^6.6.2",
|
||||
"babel-preset-react": "^6.23.0",
|
||||
"babel-preset-stage-0": "^6.22.0",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"chromedriver": "^2.30.1",
|
||||
"bundlesize": "^0.17.0",
|
||||
"chromedriver": "^2.38.3",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"css-loader": "0.28.4",
|
||||
"deep-extend": "^0.5.0",
|
||||
"deepmerge": "^1.3.2",
|
||||
"css-loader": "^0.28.11",
|
||||
"deepmerge": "^2.1.0",
|
||||
"enzyme": "^2.7.1",
|
||||
"eslint": "^4.1.1",
|
||||
"eslint-plugin-import": "^2.6.0",
|
||||
"eslint-plugin-import": "^2.13.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"eslint-plugin-react": "^7.1.0",
|
||||
"extract-text-webpack-plugin": "^2.1.2",
|
||||
"file-loader": "0.11.2",
|
||||
"eslint-plugin-react": "~7.7.0",
|
||||
"expect": "^1.20.2",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"git-describe": "^4.0.1",
|
||||
"imports-loader": "0.7.1",
|
||||
"json-loader": "0.5.4",
|
||||
"json-server": "^0.11.0",
|
||||
"karma": "^1.7.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "2.0.3",
|
||||
"less": "2.7.2",
|
||||
"license-checker": "^11.0.0",
|
||||
"mocha": "^3.4.2",
|
||||
"imports-loader": "^0.8.0",
|
||||
"jsdom": "^11.10.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"json-server": "^0.12.2",
|
||||
"less": "^3.0.2",
|
||||
"license-checker": "^19.0.0",
|
||||
"mocha": "^5.1.1",
|
||||
"nightwatch": "^0.9.16",
|
||||
"node-sass": "^4.5.0",
|
||||
"npm-run-all": "4.0.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"null-loader": "0.1.1",
|
||||
"nyc": "^11.3.0",
|
||||
"open": "0.0.5",
|
||||
"postcss-loader": "2.0.6",
|
||||
"postcss-loader": "^2.1.5",
|
||||
"raw-loader": "0.5.1",
|
||||
"react-hot-loader": "^1.3.1",
|
||||
"react-test-renderer": "^15.5.4",
|
||||
"rimraf": "^2.6.0",
|
||||
"sass-loader": "^6.0.2",
|
||||
"selenium-server-standalone-jar": "3.4.0",
|
||||
"standard": "^10.0.2",
|
||||
"sass-loader": "^7.0.1",
|
||||
"selenium-server-standalone-jar": "3.12.0",
|
||||
"standard": "^11.0.1",
|
||||
"standard-loader": "^6.0.1",
|
||||
"style-loader": "0.18.2",
|
||||
"style-loader": "^0.21.0",
|
||||
"tachyons-sass": "^4.9.2",
|
||||
"url-loader": "0.5.9",
|
||||
"webpack": "^2.6.1",
|
||||
"webpack-bundle-size-analyzer": "^2.5.0"
|
||||
"uglifyjs-webpack-plugin": "^1.2.5",
|
||||
"url-loader": "^1.0.1",
|
||||
"webpack": "^3.1.0",
|
||||
"webpack-bundle-size-analyzer": "^2.5.0",
|
||||
"webpack-cli": "^2.0.4",
|
||||
"worker-loader": "^1.1.1"
|
||||
},
|
||||
"config": {
|
||||
"deps_check_dir": ".deps_check"
|
||||
@@ -159,12 +147,19 @@
|
||||
"IE 11"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"webpack-dev-server": "2.5.0"
|
||||
"webpack-dev-server": "^2.11.1"
|
||||
},
|
||||
"nyc": {
|
||||
"all": true,
|
||||
"include": [
|
||||
"**/src/core/plugins/**.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
"bundlesize": [
|
||||
{
|
||||
"path": "./dist/swagger-ui-bundle.js",
|
||||
"maxSize": "1.5 MB",
|
||||
"compression": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"rules": {
|
||||
"import/no-extraneous-dependencies": [
|
||||
2,
|
||||
{
|
||||
"devDependencies": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ export default class ArrayModel extends Component {
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
name: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
required: PropTypes.bool,
|
||||
expandDepth: PropTypes.number,
|
||||
specPath: ImPropTypes.list.isRequired,
|
||||
@@ -18,10 +19,10 @@ export default class ArrayModel extends Component {
|
||||
}
|
||||
|
||||
render(){
|
||||
let { getComponent, getConfigs, schema, depth, expandDepth, name, specPath } = this.props
|
||||
let { getComponent, getConfigs, schema, depth, expandDepth, name, displayName, specPath } = this.props
|
||||
let description = schema.get("description")
|
||||
let items = schema.get("items")
|
||||
let title = schema.get("title") || name
|
||||
let title = schema.get("title") || displayName || name
|
||||
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref"].indexOf(key) === -1 )
|
||||
|
||||
const Markdown = getComponent("Markdown")
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Collapse } from "react-collapse"
|
||||
import { presets } from "react-motion"
|
||||
import ObjectInspector from "react-object-inspector"
|
||||
import ObjectInspector from "react-inspector"
|
||||
import Perf from "react-addons-perf"
|
||||
|
||||
export default class Debug extends React.Component {
|
||||
|
||||
@@ -7,7 +7,8 @@ export default class HighlightCode extends Component {
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
downloadable: PropTypes.bool
|
||||
downloadable: PropTypes.bool,
|
||||
fileName: PropTypes.string
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -23,7 +24,7 @@ export default class HighlightCode extends Component {
|
||||
}
|
||||
|
||||
downloadText = () => {
|
||||
saveAs(this.props.value, "response.txt")
|
||||
saveAs(this.props.value, this.props.fileName || "response.txt")
|
||||
}
|
||||
|
||||
preventYScrollingBeyondElement = (e) => {
|
||||
|
||||
@@ -6,63 +6,35 @@ export default class BaseLayout extends React.Component {
|
||||
static propTypes = {
|
||||
errSelectors: PropTypes.object.isRequired,
|
||||
errActions: PropTypes.object.isRequired,
|
||||
specActions: PropTypes.object.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
oas3Selectors: PropTypes.object.isRequired,
|
||||
oas3Actions: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onFilterChange =(e) => {
|
||||
let {target: {value}} = e
|
||||
this.props.layoutActions.updateFilter(value)
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
specSelectors,
|
||||
specActions,
|
||||
getComponent,
|
||||
layoutSelectors,
|
||||
oas3Selectors,
|
||||
oas3Actions
|
||||
} = this.props
|
||||
|
||||
let info = specSelectors.info()
|
||||
let url = specSelectors.url()
|
||||
let basePath = specSelectors.basePath()
|
||||
let host = specSelectors.host()
|
||||
let securityDefinitions = specSelectors.securityDefinitions()
|
||||
let externalDocs = specSelectors.externalDocs()
|
||||
let schemes = specSelectors.schemes()
|
||||
let servers = specSelectors.servers()
|
||||
let {specSelectors, getComponent} = this.props
|
||||
|
||||
let SvgAssets = getComponent("SvgAssets")
|
||||
let Info = getComponent("info")
|
||||
let InfoContainer = getComponent("InfoContainer", true)
|
||||
let VersionPragmaFilter = getComponent("VersionPragmaFilter")
|
||||
let Operations = getComponent("operations", true)
|
||||
let Models = getComponent("Models", true)
|
||||
let AuthorizeBtn = getComponent("authorizeBtn", true)
|
||||
let Row = getComponent("Row")
|
||||
let Col = getComponent("Col")
|
||||
let Servers = getComponent("Servers")
|
||||
let ServersContainer = getComponent("ServersContainer", true)
|
||||
let Errors = getComponent("errors", true)
|
||||
|
||||
let isLoading = specSelectors.loadingStatus() === "loading"
|
||||
let isFailed = specSelectors.loadingStatus() === "failed"
|
||||
let filter = layoutSelectors.currentFilter()
|
||||
|
||||
let inputStyle = {}
|
||||
if(isFailed) inputStyle.color = "red"
|
||||
if(isLoading) inputStyle.color = "#aaa"
|
||||
|
||||
const Schemes = getComponent("schemes")
|
||||
const SchemesContainer = getComponent("SchemesContainer", true)
|
||||
const FilterContainer = getComponent("FilterContainer", true)
|
||||
let isSwagger2 = specSelectors.isSwagger2()
|
||||
let isOAS3 = specSelectors.isOAS3()
|
||||
|
||||
const isSpecEmpty = !specSelectors.specStr()
|
||||
|
||||
if(isSpecEmpty) {
|
||||
let loadingMessage
|
||||
let isLoading = specSelectors.loadingStatus() === "loading"
|
||||
if(isLoading) {
|
||||
loadingMessage = <div className="loading"></div>
|
||||
} else {
|
||||
@@ -80,57 +52,19 @@ export default class BaseLayout extends React.Component {
|
||||
|
||||
<div className='swagger-ui'>
|
||||
<SvgAssets />
|
||||
<div>
|
||||
<VersionPragmaFilter isSwagger2={isSwagger2} isOAS3={isOAS3} alsoShow={<Errors/>}>
|
||||
<Errors/>
|
||||
<Row className="information-container">
|
||||
<Col mobile={12}>
|
||||
{ info.count() ? (
|
||||
<Info info={ info } url={ url } host={ host } basePath={ basePath } externalDocs={externalDocs} getComponent={getComponent}/>
|
||||
) : null }
|
||||
<InfoContainer/>
|
||||
</Col>
|
||||
</Row>
|
||||
{ schemes && schemes.size || securityDefinitions ? (
|
||||
<div className="scheme-container">
|
||||
<Col className="schemes wrapper" mobile={12}>
|
||||
{ schemes && schemes.size ? (
|
||||
<Schemes
|
||||
currentScheme={specSelectors.operationScheme()}
|
||||
schemes={ schemes }
|
||||
specActions={ specActions } />
|
||||
) : null }
|
||||
|
||||
{ securityDefinitions ? (
|
||||
<AuthorizeBtn />
|
||||
) : null }
|
||||
</Col>
|
||||
</div>
|
||||
) : null }
|
||||
<SchemesContainer/>
|
||||
|
||||
{ servers && servers.size ? (
|
||||
<div className="global-server-container">
|
||||
<Col className="servers wrapper" mobile={12}>
|
||||
<span className="servers-title">Server</span>
|
||||
<Servers
|
||||
servers={servers}
|
||||
currentServer={oas3Selectors.selectedServer()}
|
||||
setSelectedServer={oas3Actions.setSelectedServer}
|
||||
setServerVariableValue={oas3Actions.setServerVariableValue}
|
||||
getServerVariable={oas3Selectors.serverVariableValue}
|
||||
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
|
||||
/>
|
||||
</Col>
|
||||
</div>
|
||||
<ServersContainer/>
|
||||
|
||||
) : null}
|
||||
|
||||
{
|
||||
filter === null || filter === false ? null :
|
||||
<div className="filter-container">
|
||||
<Col className="filter wrapper" mobile={12}>
|
||||
<input className="operation-filter-input" placeholder="Filter by tag" type="text" onChange={this.onFilterChange} value={filter === true || filter === "true" ? "" : filter} disabled={isLoading} style={inputStyle} />
|
||||
</Col>
|
||||
</div>
|
||||
}
|
||||
<FilterContainer/>
|
||||
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
@@ -142,7 +76,7 @@ export default class BaseLayout extends React.Component {
|
||||
<Models/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</VersionPragmaFilter>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export default class ModelWrapper extends Component {
|
||||
static propTypes = {
|
||||
schema: PropTypes.object.isRequired,
|
||||
name: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
|
||||
@@ -10,6 +10,7 @@ export default class Model extends ImmutablePureComponent {
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
name: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
isRef: PropTypes.bool,
|
||||
required: PropTypes.bool,
|
||||
expandDepth: PropTypes.number,
|
||||
@@ -33,7 +34,7 @@ export default class Model extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { getComponent, getConfigs, specSelectors, schema, required, name, isRef, specPath } = this.props
|
||||
let { getComponent, getConfigs, specSelectors, schema, required, name, isRef, specPath, displayName } = this.props
|
||||
const ObjectModel = getComponent("ObjectModel")
|
||||
const ArrayModel = getComponent("ArrayModel")
|
||||
const PrimitiveModel = getComponent("PrimitiveModel")
|
||||
@@ -51,7 +52,7 @@ export default class Model extends ImmutablePureComponent {
|
||||
|
||||
if(!schema) {
|
||||
return <span className="model model-title">
|
||||
<span className="model-title__text">{ name }</span>
|
||||
<span className="model-title__text">{ displayName || name }</span>
|
||||
<img src={require("core/../img/rolling-load.svg")} height={"20px"} width={"20px"} style={{
|
||||
marginLeft: "1em",
|
||||
position: "relative",
|
||||
|
||||
@@ -41,6 +41,7 @@ export default class Models extends Component {
|
||||
const ModelWrapper = getComponent("ModelWrapper")
|
||||
const Collapse = getComponent("Collapse")
|
||||
const ModelCollapse = getComponent("ModelCollapse")
|
||||
const JumpToPath = getComponent("JumpToPath")
|
||||
|
||||
return <section className={ showModels ? "models is-open" : "models"}>
|
||||
<h4 onClick={() => layoutActions.show("models", !showModels)}>
|
||||
@@ -51,9 +52,12 @@ export default class Models extends Component {
|
||||
</h4>
|
||||
<Collapse isOpened={showModels}>
|
||||
{
|
||||
definitions.entrySeq().map( ( [ name ])=>{
|
||||
definitions.entrySeq().map(([name])=>{
|
||||
|
||||
const schema = specSelectors.specResolvedSubtree([...specPathBase, name])
|
||||
const fullPath = [...specPathBase, name]
|
||||
const schema = specSelectors.specResolvedSubtree(fullPath)|| Im.Map()
|
||||
const rawSchema = specSelectors.specJson().getIn(fullPath, Im.Map())
|
||||
const displayName = schema.get("title") || rawSchema.get("title") || name
|
||||
|
||||
if(layoutSelectors.isShown(["models", name], false) && schema === undefined) {
|
||||
// Firing an action in a container render is not great,
|
||||
@@ -61,10 +65,13 @@ export default class Models extends Component {
|
||||
this.props.specActions.requestResolvedSubtree([...this.getSchemaBasePath(), name])
|
||||
}
|
||||
|
||||
const specPath = Im.List([...specPathBase, name])
|
||||
|
||||
const content = <ModelWrapper name={ name }
|
||||
expandDepth={ defaultModelsExpandDepth }
|
||||
schema={ schema || Im.Map() }
|
||||
specPath={Im.List([...specPathBase, name])}
|
||||
schema={ schema || Im.Map() }
|
||||
displayName={displayName}
|
||||
specPath={specPath}
|
||||
getComponent={ getComponent }
|
||||
specSelectors={ specSelectors }
|
||||
getConfigs = {getConfigs}
|
||||
@@ -72,15 +79,19 @@ export default class Models extends Component {
|
||||
layoutActions = {layoutActions}/>
|
||||
|
||||
const title = <span className="model-box">
|
||||
<span className="model model-title">{name}</span>
|
||||
<span className="model model-title">
|
||||
{displayName}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
return <div id={ `model-${name}` } className="model-container" key={ `models-section-${name}` }>
|
||||
<span className="models-jump-to-path"><JumpToPath specPath={specPath} /></span>
|
||||
<ModelCollapse
|
||||
classes="model-box"
|
||||
collapsedContent={this.getCollapsedContent(name)}
|
||||
onToggle={this.handleToggle}
|
||||
title={title}
|
||||
displayName={displayName}
|
||||
modelName={name}
|
||||
hideSelfOnExpand={true}
|
||||
expanded={defaultModelsExpandDepth > 1}
|
||||
|
||||
@@ -15,6 +15,7 @@ export default class ObjectModel extends Component {
|
||||
onToggle: PropTypes.func,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
name: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
isRef: PropTypes.bool,
|
||||
expandDepth: PropTypes.number,
|
||||
depth: PropTypes.number,
|
||||
@@ -22,7 +23,7 @@ export default class ObjectModel extends Component {
|
||||
}
|
||||
|
||||
render(){
|
||||
let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props
|
||||
let { schema, name, displayName, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props
|
||||
let { specSelectors,expandDepth } = otherProps
|
||||
const { isOAS3 } = specSelectors
|
||||
|
||||
@@ -35,7 +36,7 @@ export default class ObjectModel extends Component {
|
||||
let description = schema.get("description")
|
||||
let properties = schema.get("properties")
|
||||
let additionalProperties = schema.get("additionalProperties")
|
||||
let title = schema.get("title") || name
|
||||
let title = schema.get("title") || displayName || name
|
||||
let requiredProperties = schema.get("required")
|
||||
|
||||
const JumpToPath = getComponent("JumpToPath", true)
|
||||
@@ -78,7 +79,7 @@ export default class ObjectModel extends Component {
|
||||
{
|
||||
<table className="model"><tbody>
|
||||
{
|
||||
!description ? null : <tr style={{ color: "#999", fontStyle: "italic" }}>
|
||||
!description ? null : <tr style={{ color: "#666", fontStyle: "italic" }}>
|
||||
<td>description:</td>
|
||||
<td>
|
||||
<Markdown source={ description } />
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from "react"
|
||||
import URL from "url-parse"
|
||||
|
||||
import PropTypes from "prop-types"
|
||||
import { sanitizeUrl } from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
export default class OnlineValidatorBadge extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -11,20 +14,28 @@ export default class OnlineValidatorBadge extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
let { specSelectors, getConfigs } = props
|
||||
let { getConfigs } = props
|
||||
let { validatorUrl } = getConfigs()
|
||||
this.state = {
|
||||
url: specSelectors.url(),
|
||||
url: this.getDefinitionUrl(),
|
||||
validatorUrl: validatorUrl === undefined ? "https://online.swagger.io/validator" : validatorUrl
|
||||
}
|
||||
}
|
||||
|
||||
getDefinitionUrl = () => {
|
||||
// TODO: test this behavior by stubbing `window.location` in an Enzyme/JSDom env
|
||||
let { specSelectors } = this.props
|
||||
|
||||
const urlObject = new URL(specSelectors.url(), win.location)
|
||||
return urlObject.toString()
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let { specSelectors, getConfigs } = nextProps
|
||||
let { getConfigs } = nextProps
|
||||
let { validatorUrl } = getConfigs()
|
||||
|
||||
this.setState({
|
||||
url: specSelectors.url(),
|
||||
url: this.getDefinitionUrl(),
|
||||
validatorUrl: validatorUrl === undefined ? "https://online.swagger.io/validator" : validatorUrl
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import Im from "immutable"
|
||||
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
|
||||
|
||||
export default class OperationTag extends React.Component {
|
||||
|
||||
static defaultProps = {
|
||||
tagObj: Im.fromJS({}),
|
||||
tag: "",
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
tagObj: ImPropTypes.map.isRequired,
|
||||
tag: PropTypes.string.isRequired,
|
||||
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
|
||||
children: PropTypes.element,
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tagObj,
|
||||
tag,
|
||||
children,
|
||||
|
||||
layoutSelectors,
|
||||
layoutActions,
|
||||
getConfigs,
|
||||
getComponent,
|
||||
} = this.props
|
||||
|
||||
let {
|
||||
docExpansion,
|
||||
deepLinking,
|
||||
} = getConfigs()
|
||||
|
||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||
|
||||
const Collapse = getComponent("Collapse")
|
||||
const Markdown = getComponent("Markdown")
|
||||
const DeepLink = getComponent("DeepLink")
|
||||
|
||||
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
||||
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
||||
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
||||
|
||||
let isShownKey = ["operations-tag", createDeepLinkPath(tag)]
|
||||
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||
|
||||
return (
|
||||
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} >
|
||||
|
||||
<h4
|
||||
onClick={() => layoutActions.show(isShownKey, !showTag)}
|
||||
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
|
||||
id={isShownKey.join("-")}>
|
||||
<DeepLink
|
||||
enabled={isDeepLinkingEnabled}
|
||||
isShown={showTag}
|
||||
path={tag}
|
||||
text={tag} />
|
||||
{ !tagDescription ? <small></small> :
|
||||
<small>
|
||||
<Markdown source={tagDescription} />
|
||||
</small>
|
||||
}
|
||||
|
||||
<div>
|
||||
{ !tagExternalDocsDescription ? null :
|
||||
<small>
|
||||
{ tagExternalDocsDescription }
|
||||
{ tagExternalDocsUrl ? ": " : null }
|
||||
{ tagExternalDocsUrl ?
|
||||
<a
|
||||
href={sanitizeUrl(tagExternalDocsUrl)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
target={"_blank"}
|
||||
>{tagExternalDocsUrl}</a> : null
|
||||
}
|
||||
</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="expand-operation"
|
||||
title={showTag ? "Collapse operation": "Expand operation"}
|
||||
onClick={() => layoutActions.show(isShownKey, !showTag)}>
|
||||
|
||||
<svg className="arrow" width="20" height="20">
|
||||
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
|
||||
</svg>
|
||||
</button>
|
||||
</h4>
|
||||
|
||||
<Collapse isOpened={showTag}>
|
||||
{children}
|
||||
</Collapse>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import Im from "immutable"
|
||||
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
|
||||
|
||||
const SWAGGER2_OPERATION_METHODS = [
|
||||
"get", "put", "post", "delete", "options", "head", "patch"
|
||||
@@ -38,18 +37,12 @@ export default class Operations extends React.Component {
|
||||
let taggedOps = specSelectors.taggedOperations()
|
||||
|
||||
const OperationContainer = getComponent("OperationContainer", true)
|
||||
const Collapse = getComponent("Collapse")
|
||||
const Markdown = getComponent("Markdown")
|
||||
const DeepLink = getComponent("DeepLink")
|
||||
const OperationTag = getComponent("OperationTag")
|
||||
|
||||
let {
|
||||
docExpansion,
|
||||
maxDisplayedTags,
|
||||
deepLinking
|
||||
} = getConfigs()
|
||||
|
||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||
|
||||
let filter = layoutSelectors.currentFilter()
|
||||
|
||||
if (filter) {
|
||||
@@ -66,88 +59,49 @@ export default class Operations extends React.Component {
|
||||
<div>
|
||||
{
|
||||
taggedOps.map( (tagObj, tag) => {
|
||||
let operations = tagObj.get("operations")
|
||||
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
||||
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
||||
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
||||
|
||||
let isShownKey = ["operations-tag", createDeepLinkPath(tag)]
|
||||
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||
|
||||
const operations = tagObj.get("operations")
|
||||
return (
|
||||
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}>
|
||||
|
||||
<h4
|
||||
onClick={() => layoutActions.show(isShownKey, !showTag)}
|
||||
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
|
||||
id={isShownKey.join("-")}>
|
||||
<DeepLink
|
||||
enabled={isDeepLinkingEnabled}
|
||||
isShown={showTag}
|
||||
path={tag}
|
||||
text={tag} />
|
||||
{ !tagDescription ? <small></small> :
|
||||
<small>
|
||||
<Markdown source={tagDescription} />
|
||||
</small>
|
||||
}
|
||||
|
||||
<div>
|
||||
{ !tagExternalDocsDescription ? null :
|
||||
<small>
|
||||
{ tagExternalDocsDescription }
|
||||
{ tagExternalDocsUrl ? ": " : null }
|
||||
{ tagExternalDocsUrl ?
|
||||
<a
|
||||
href={sanitizeUrl(tagExternalDocsUrl)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
target={"_blank"}
|
||||
>{tagExternalDocsUrl}</a> : null
|
||||
}
|
||||
</small>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button className="expand-operation" title={showTag ? "Collapse operation": "Expand operation"} onClick={() => layoutActions.show(isShownKey, !showTag)}>
|
||||
<svg className="arrow" width="20" height="20">
|
||||
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
|
||||
</svg>
|
||||
</button>
|
||||
</h4>
|
||||
|
||||
<Collapse isOpened={showTag}>
|
||||
{
|
||||
operations.map( op => {
|
||||
const path = op.get("path")
|
||||
const method = op.get("method")
|
||||
const specPath = Im.List(["paths", path, method])
|
||||
<OperationTag
|
||||
key={"operation-" + tag}
|
||||
tagObj={tagObj}
|
||||
tag={tag}
|
||||
layoutSelectors={layoutSelectors}
|
||||
layoutActions={layoutActions}
|
||||
getConfigs={getConfigs}
|
||||
getComponent={getComponent}>
|
||||
{
|
||||
operations.map( op => {
|
||||
const path = op.get("path")
|
||||
const method = op.get("method")
|
||||
const specPath = Im.List(["paths", path, method])
|
||||
|
||||
|
||||
// FIXME: (someday) this logic should probably be in a selector,
|
||||
// but doing so would require further opening up
|
||||
// selectors to the plugin system, to allow for dynamic
|
||||
// overriding of low-level selectors that other selectors
|
||||
// rely on. --KS, 12/17
|
||||
const validMethods = specSelectors.isOAS3() ?
|
||||
OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS
|
||||
// FIXME: (someday) this logic should probably be in a selector,
|
||||
// but doing so would require further opening up
|
||||
// selectors to the plugin system, to allow for dynamic
|
||||
// overriding of low-level selectors that other selectors
|
||||
// rely on. --KS, 12/17
|
||||
const validMethods = specSelectors.isOAS3() ?
|
||||
OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS
|
||||
|
||||
if(validMethods.indexOf(method) === -1) {
|
||||
return null
|
||||
}
|
||||
if(validMethods.indexOf(method) === -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <OperationContainer
|
||||
key={`${path}-${method}`}
|
||||
specPath={specPath}
|
||||
op={op}
|
||||
path={path}
|
||||
method={method}
|
||||
tag={tag}
|
||||
/>
|
||||
}).toArray()
|
||||
}
|
||||
</Collapse>
|
||||
</div>
|
||||
)
|
||||
return <OperationContainer
|
||||
key={`${path}-${method}`}
|
||||
specPath={specPath}
|
||||
op={op}
|
||||
path={path}
|
||||
method={method}
|
||||
tag={tag}
|
||||
/>
|
||||
}).toArray()
|
||||
}
|
||||
|
||||
|
||||
</OperationTag>
|
||||
)
|
||||
}).toArray()
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,10 @@ export default class ParamBody extends PureComponent {
|
||||
}
|
||||
|
||||
updateValues = (props) => {
|
||||
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
|
||||
let parameter = specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : fromJS({})
|
||||
let { param, isExecute, consumesValue="" } = props
|
||||
let isXml = /xml/i.test(consumesValue)
|
||||
let isJson = /json/i.test(consumesValue)
|
||||
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
||||
let paramValue = isXml ? param.get("value_xml") : param.get("value")
|
||||
|
||||
if ( paramValue !== undefined ) {
|
||||
let val = !paramValue && isJson ? "{}" : paramValue
|
||||
@@ -79,7 +78,7 @@ export default class ParamBody extends PureComponent {
|
||||
this._onChange(value, isXml)
|
||||
}
|
||||
|
||||
_onChange = (val, isXml) => { (this.props.onChange || NOOP)(this.props.param, val, isXml) }
|
||||
_onChange = (val, isXml) => { (this.props.onChange || NOOP)(val, isXml) }
|
||||
|
||||
handleOnChange = e => {
|
||||
const {consumesValue} = this.props
|
||||
@@ -107,7 +106,7 @@ export default class ParamBody extends PureComponent {
|
||||
const HighlightCode = getComponent("highlightCode")
|
||||
const ContentType = getComponent("contentType")
|
||||
// for domains where specSelectors not passed
|
||||
let parameter = specSelectors ? specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) : param
|
||||
let parameter = specSelectors ? specSelectors.parameterWithMetaByIdentity(pathMethod, param) : param
|
||||
let errors = parameter.get("errors", List())
|
||||
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
|
||||
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
|
||||
|
||||
@@ -9,6 +9,7 @@ export default class ParameterRow extends Component {
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
param: PropTypes.object.isRequired,
|
||||
rawParam: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
fn: PropTypes.object.isRequired,
|
||||
isExecute: PropTypes.bool,
|
||||
@@ -22,20 +23,7 @@ export default class ParameterRow extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
let { specSelectors, pathMethod, param } = props
|
||||
let defaultValue = param.get("default")
|
||||
let xExampleValue = param.get("x-example")
|
||||
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
|
||||
let value = parameter ? parameter.get("value") : ""
|
||||
|
||||
if( param.get("in") !== "body" ) {
|
||||
if ( xExampleValue !== undefined && value === undefined && specSelectors.isSwagger2() ) {
|
||||
this.onChangeWrapper(xExampleValue)
|
||||
} else if ( defaultValue !== undefined && value === undefined ) {
|
||||
this.onChangeWrapper(defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
this.setDefaultValue()
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
@@ -43,8 +31,7 @@ export default class ParameterRow extends Component {
|
||||
let { isOAS3 } = specSelectors
|
||||
|
||||
let example = param.get("example")
|
||||
let defaultValue = param.get("default")
|
||||
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
|
||||
let parameter = specSelectors.parameterWithMetaByIdentity(pathMethod, param) || param
|
||||
let enumValue
|
||||
|
||||
if(isOAS3()) {
|
||||
@@ -61,8 +48,6 @@ export default class ParameterRow extends Component {
|
||||
value = paramValue
|
||||
} else if ( example !== undefined ) {
|
||||
value = example
|
||||
} else if ( defaultValue !== undefined) {
|
||||
value = defaultValue
|
||||
} else if ( param.get("required") && enumValue && enumValue.size ) {
|
||||
value = enumValue.first()
|
||||
}
|
||||
@@ -72,13 +57,36 @@ export default class ParameterRow extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
onChangeWrapper = (value) => {
|
||||
let { onChange, param } = this.props
|
||||
return onChange(param, value)
|
||||
onChangeWrapper = (value, isXml = false) => {
|
||||
let { onChange, rawParam } = this.props
|
||||
return onChange(rawParam, value, isXml)
|
||||
}
|
||||
|
||||
setDefaultValue = () => {
|
||||
let { specSelectors, pathMethod, param } = this.props
|
||||
|
||||
if (param.get("value") !== undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
let schema = specSelectors.isOAS3() ? param.get("schema", Map({})) : param
|
||||
|
||||
let defaultValue = schema.get("default")
|
||||
let xExampleValue = param.get("x-example") // Swagger 2 only
|
||||
let parameter = specSelectors.parameterWithMetaByIdentity(pathMethod, param)
|
||||
let value = parameter ? parameter.get("value") : ""
|
||||
|
||||
if( param.get("in") !== "body" ) {
|
||||
if ( xExampleValue !== undefined && value === undefined && specSelectors.isSwagger2() ) {
|
||||
this.onChangeWrapper(xExampleValue)
|
||||
} else if ( defaultValue !== undefined && value === undefined ) {
|
||||
this.onChangeWrapper(defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let {param, onChange, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod, specPath} = this.props
|
||||
let {param, rawParam, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod, specPath} = this.props
|
||||
|
||||
let { isOAS3 } = specSelectors
|
||||
|
||||
@@ -94,7 +102,7 @@ export default class ParameterRow extends Component {
|
||||
param={param}
|
||||
consumes={ specSelectors.operationConsumes(pathMethod) }
|
||||
consumesValue={ specSelectors.contentTypeValues(pathMethod).get("requestContentType") }
|
||||
onChange={onChange}
|
||||
onChange={this.onChangeWrapper}
|
||||
onChangeConsumes={onChangeConsumes}
|
||||
isExecute={ isExecute }
|
||||
specSelectors={ specSelectors }
|
||||
@@ -105,7 +113,7 @@ export default class ParameterRow extends Component {
|
||||
const Markdown = getComponent("Markdown")
|
||||
const ParameterExt = getComponent("ParameterExt")
|
||||
|
||||
let paramWithMeta = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
|
||||
let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
|
||||
let format = param.get("format")
|
||||
let schema = isOAS3 && isOAS3() ? param.get("schema") : param
|
||||
let type = schema.get("type")
|
||||
@@ -149,7 +157,7 @@ export default class ParameterRow extends Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<tr className="parameters">
|
||||
<td className="col parameters-col_name">
|
||||
<div className={required ? "parameter__name required" : "parameter__name"}>
|
||||
{ param.get("name") }
|
||||
|
||||
@@ -36,11 +36,11 @@ export default class Parameters extends Component {
|
||||
|
||||
onChange = ( param, value, isXml ) => {
|
||||
let {
|
||||
specActions: { changeParam },
|
||||
specActions: { changeParamByIdentity },
|
||||
onChangeKey,
|
||||
} = this.props
|
||||
|
||||
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||
changeParamByIdentity(onChangeKey, param, value, isXml)
|
||||
}
|
||||
|
||||
onChangeConsumesWrapper = ( val ) => {
|
||||
@@ -101,7 +101,8 @@ export default class Parameters extends Component {
|
||||
specPath={specPath.push(i.toString())}
|
||||
getComponent={ getComponent }
|
||||
getConfigs={ getConfigs }
|
||||
param={ specSelectors.parameterWithMeta(pathMethod, parameter.get("name"), parameter.get("in")) }
|
||||
rawParam={ parameter }
|
||||
param={ specSelectors.parameterWithMetaByIdentity(pathMethod, parameter) }
|
||||
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
|
||||
onChange={ this.onChange }
|
||||
onChangeConsumes={this.onChangeConsumesWrapper}
|
||||
|
||||
@@ -10,11 +10,12 @@ export default class Primitive extends Component {
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
name: PropTypes.string,
|
||||
displayName: PropTypes.string,
|
||||
depth: PropTypes.number
|
||||
}
|
||||
|
||||
render(){
|
||||
let { schema, getComponent, getConfigs, name, depth } = this.props
|
||||
let { schema, getComponent, getConfigs, name, displayName, depth } = this.props
|
||||
|
||||
const { showExtensions } = getConfigs()
|
||||
|
||||
@@ -27,7 +28,7 @@ export default class Primitive extends Component {
|
||||
let format = schema.get("format")
|
||||
let xml = schema.get("xml")
|
||||
let enumArray = schema.get("enum")
|
||||
let title = schema.get("title") || name
|
||||
let title = schema.get("title") || displayName || name
|
||||
let description = schema.get("description")
|
||||
let extensions = getExtensions(schema)
|
||||
let properties = schema
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import Remarkable from "remarkable"
|
||||
import sanitize from "sanitize-html"
|
||||
import DomPurify from "dompurify"
|
||||
import cx from "classnames"
|
||||
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
@@ -40,20 +40,8 @@ Markdown.propTypes = {
|
||||
|
||||
export default Markdown
|
||||
|
||||
const sanitizeOptions = {
|
||||
allowedTags: sanitize.defaults.allowedTags.concat([ "h1", "h2", "img", "span" ]),
|
||||
allowedAttributes: {
|
||||
...sanitize.defaults.allowedAttributes,
|
||||
"img": sanitize.defaults.allowedAttributes.img.concat(["title"]),
|
||||
"td": [ "colspan" ],
|
||||
"*": [ "class" ]
|
||||
},
|
||||
allowedSchemesByTag: { img: [ "http", "https", "data" ] },
|
||||
textFilter: function(text) {
|
||||
return text.replace(/"/g, "\"")
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizer(str) {
|
||||
return sanitize(str, sanitizeOptions)
|
||||
return DomPurify.sanitize(str, {
|
||||
ADD_ATTR: ["target"]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ export default class ResponseBody extends React.PureComponent {
|
||||
let { content, contentType, url, headers={}, getComponent } = this.props
|
||||
const { parsedContent } = this.state
|
||||
const HighlightCode = getComponent("highlightCode")
|
||||
const downloadName = "response_" + new Date().getTime()
|
||||
let body, bodyEl
|
||||
url = url || ""
|
||||
|
||||
@@ -63,9 +64,7 @@ export default class ResponseBody extends React.PureComponent {
|
||||
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
|
||||
// Download
|
||||
|
||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
||||
|
||||
if (!isSafari && "Blob" in window) {
|
||||
if ("Blob" in window) {
|
||||
let type = contentType || "text/html"
|
||||
let blob = (content instanceof Blob) ? content : new Blob([content], {type: type})
|
||||
let href = window.URL.createObjectURL(blob)
|
||||
@@ -100,7 +99,7 @@ export default class ResponseBody extends React.PureComponent {
|
||||
body = "can't parse JSON. Raw result:\n\n" + content
|
||||
}
|
||||
|
||||
bodyEl = <HighlightCode downloadable value={ body } />
|
||||
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.json`} value={ body } />
|
||||
|
||||
// XML
|
||||
} else if (/xml/i.test(contentType)) {
|
||||
@@ -108,11 +107,11 @@ export default class ResponseBody extends React.PureComponent {
|
||||
textNodesOnSameLine: true,
|
||||
indentor: " "
|
||||
})
|
||||
bodyEl = <HighlightCode downloadable value={ body } />
|
||||
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.xml`} value={ body } />
|
||||
|
||||
// HTML or Plain Text
|
||||
} else if (lowerCase(contentType) === "text/html" || /text\/plain/.test(contentType)) {
|
||||
bodyEl = <HighlightCode downloadable value={ content } />
|
||||
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.html`} value={ content } />
|
||||
|
||||
// Image
|
||||
} else if (/^image\//i.test(contentType)) {
|
||||
@@ -126,7 +125,7 @@ export default class ResponseBody extends React.PureComponent {
|
||||
} else if (/^audio\//i.test(contentType)) {
|
||||
bodyEl = <pre><audio controls><source src={ url } type={ contentType } /></audio></pre>
|
||||
} else if (typeof content === "string") {
|
||||
bodyEl = <HighlightCode downloadable value={ content } />
|
||||
bodyEl = <HighlightCode downloadable fileName={`${downloadName}.txt`} value={ content } />
|
||||
} else if ( content.size > 0 ) {
|
||||
// We don't know the contentType, but there was some content returned
|
||||
if(parsedContent) {
|
||||
@@ -136,7 +135,7 @@ export default class ResponseBody extends React.PureComponent {
|
||||
<p className="i">
|
||||
Unrecognized response type; displaying content as text.
|
||||
</p>
|
||||
<HighlightCode downloadable value={ parsedContent } />
|
||||
<HighlightCode downloadable fileName={`${downloadName}.txt`} value={ parsedContent } />
|
||||
</div>
|
||||
|
||||
} else {
|
||||
|
||||
@@ -21,8 +21,8 @@ export default class TryItOutButton extends React.Component {
|
||||
return (
|
||||
<div className="try-out">
|
||||
{
|
||||
enabled ? <button className="btn try-out__btn cancel" onClick={ onTryoutClick }>Cancel</button>
|
||||
: <button className="btn try-out__btn" onClick={ onCancelClick }>Try it out </button>
|
||||
enabled ? <button className="btn try-out__btn cancel" onClick={ onCancelClick }>Cancel</button>
|
||||
: <button className="btn try-out__btn" onClick={ onTryoutClick }>Try it out </button>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
export default class VersionPragmaFilter extends React.PureComponent {
|
||||
static propTypes = {
|
||||
isSwagger2: PropTypes.bool.isRequired,
|
||||
isOAS3: PropTypes.bool.isRequired,
|
||||
bypass: PropTypes.bool,
|
||||
alsoShow: PropTypes.element,
|
||||
children: PropTypes.any,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
alsoShow: null,
|
||||
children: null,
|
||||
bypass: false,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { bypass, isSwagger2, isOAS3, alsoShow } = this.props
|
||||
|
||||
if(bypass) {
|
||||
return <div>{ this.props.children }</div>
|
||||
}
|
||||
|
||||
if(isSwagger2 && isOAS3) {
|
||||
return <div className="version-pragma">
|
||||
{alsoShow}
|
||||
<div className="version-pragma__message version-pragma__message--ambiguous">
|
||||
<div>
|
||||
<h3>Unable to render this definition</h3>
|
||||
<p><code>swagger</code> and <code>openapi</code> fields cannot be present in the same Swagger or OpenAPI definition. Please remove one of the fields.</p>
|
||||
<p>Supported version fields are <code>swagger: {"\"2.0\""}</code> and those that match <code>openapi: 3.0.n</code> (for example, <code>openapi: 3.0.0</code>).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
if(!isSwagger2 && !isOAS3) {
|
||||
return <div className="version-pragma">
|
||||
{alsoShow}
|
||||
<div className="version-pragma__message version-pragma__message--missing">
|
||||
<div>
|
||||
<h3>Unable to render this definition</h3>
|
||||
<p>The provided definition does not specify a valid version field.</p>
|
||||
<p>Please indicate a valid Swagger or OpenAPI version field. Supported version fields are <code>swagger: {"\"2.0\""}</code> and those that match <code>openapi: 3.0.n</code> (for example, <code>openapi: 3.0.0</code>).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div>{ this.props.children }</div>
|
||||
}
|
||||
}
|
||||
@@ -113,11 +113,11 @@ export default class OperationContainer extends PureComponent {
|
||||
layoutActions.show(["operations", tag, operationId], !isShown)
|
||||
}
|
||||
|
||||
onTryoutClick =() => {
|
||||
onCancelClick=() => {
|
||||
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
|
||||
}
|
||||
|
||||
onCancelClick =() => {
|
||||
onTryoutClick =() => {
|
||||
let { specActions, path, method } = this.props
|
||||
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
|
||||
specActions.clearValidateParams([path, method])
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
export default class FilterContainer extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
onFilterChange = (e) => {
|
||||
const {target: {value}} = e
|
||||
this.props.layoutActions.updateFilter(value)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {specSelectors, layoutSelectors, getComponent} = this.props
|
||||
const Col = getComponent("Col")
|
||||
|
||||
const isLoading = specSelectors.loadingStatus() === "loading"
|
||||
const isFailed = specSelectors.loadingStatus() === "failed"
|
||||
const filter = layoutSelectors.currentFilter()
|
||||
|
||||
const inputStyle = {}
|
||||
if (isFailed) inputStyle.color = "red"
|
||||
if (isLoading) inputStyle.color = "#aaa"
|
||||
|
||||
return (
|
||||
<div>
|
||||
{filter === null || filter === false ? null :
|
||||
<div className="filter-container">
|
||||
<Col className="filter wrapper" mobile={12}>
|
||||
<input className="operation-filter-input" placeholder="Filter by tag" type="text"
|
||||
onChange={this.onFilterChange} value={filter === true || filter === "true" ? "" : filter}
|
||||
disabled={isLoading} style={inputStyle}/>
|
||||
</Col>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
export default class InfoContainer extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
specActions: PropTypes.object.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render () {
|
||||
const {specSelectors, getComponent} = this.props
|
||||
|
||||
const info = specSelectors.info()
|
||||
const url = specSelectors.url()
|
||||
const basePath = specSelectors.basePath()
|
||||
const host = specSelectors.host()
|
||||
const externalDocs = specSelectors.externalDocs()
|
||||
|
||||
const Info = getComponent("info")
|
||||
|
||||
return (
|
||||
<div>
|
||||
{info && info.count() ? (
|
||||
<Info info={info} url={url} host={host} basePath={basePath} externalDocs={externalDocs}
|
||||
getComponent={getComponent}/>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
export default class SchemesContainer extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
specActions: PropTypes.object.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render () {
|
||||
const {specActions, specSelectors, getComponent} = this.props
|
||||
const currentScheme = specSelectors.operationScheme()
|
||||
const schemes = specSelectors.schemes()
|
||||
const securityDefinitions = specSelectors.securityDefinitions()
|
||||
|
||||
const Col = getComponent("Col")
|
||||
const AuthorizeBtn = getComponent("authorizeBtn", true)
|
||||
const Schemes = getComponent("schemes")
|
||||
|
||||
return (
|
||||
<div>
|
||||
{schemes && schemes.size || securityDefinitions ? (
|
||||
<div className="scheme-container">
|
||||
<Col className="schemes wrapper" mobile={12}>
|
||||
{schemes && schemes.size ? (
|
||||
<Schemes
|
||||
currentScheme={currentScheme}
|
||||
schemes={schemes}
|
||||
specActions={specActions}
|
||||
/>
|
||||
) : null}
|
||||
{securityDefinitions ? (
|
||||
<AuthorizeBtn/>
|
||||
) : null}
|
||||
</Col>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -27,7 +27,7 @@ module.exports = function SwaggerUI(opts) {
|
||||
|
||||
const defaults = {
|
||||
// Some general settings, that we floated to the top
|
||||
dom_id: null,
|
||||
dom_id: null, // eslint-disable-line camelcase
|
||||
domNode: null,
|
||||
spec: {},
|
||||
url: "",
|
||||
@@ -131,10 +131,6 @@ module.exports = function SwaggerUI(opts) {
|
||||
var system = store.getSystem()
|
||||
|
||||
const downloadSpec = (fetchedConfig) => {
|
||||
if(typeof constructorConfig !== "object") {
|
||||
return system
|
||||
}
|
||||
|
||||
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
||||
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
||||
|
||||
@@ -144,6 +140,7 @@ module.exports = function SwaggerUI(opts) {
|
||||
}
|
||||
|
||||
store.setConfigs(mergedConfig)
|
||||
system.configsActions.loaded()
|
||||
|
||||
if (fetchedConfig !== null) {
|
||||
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
||||
@@ -171,15 +168,17 @@ module.exports = function SwaggerUI(opts) {
|
||||
return system
|
||||
}
|
||||
|
||||
let configUrl = queryConfig.config || constructorConfig.configUrl
|
||||
const configUrl = queryConfig.config || constructorConfig.configUrl
|
||||
|
||||
if (!configUrl || !system.specActions.getConfigByUrl || system.specActions.getConfigByUrl && !system.specActions.getConfigByUrl({
|
||||
if (!configUrl || !system.specActions || !system.specActions.getConfigByUrl || system.specActions.getConfigByUrl && !system.specActions.getConfigByUrl({
|
||||
url: configUrl,
|
||||
loadRemoteConfig: true,
|
||||
requestInterceptor: constructorConfig.requestInterceptor,
|
||||
responseInterceptor: constructorConfig.responseInterceptor,
|
||||
}, downloadSpec)) {
|
||||
return downloadSpec()
|
||||
} else {
|
||||
system.specActions.getConfigByUrl(configUrl, downloadSpec)
|
||||
}
|
||||
|
||||
return system
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React, { PureComponent, Component } from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { List, fromJS } from "immutable"
|
||||
import cx from "classnames"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import DebounceInput from "react-debounce-input"
|
||||
import { getSampleSchema } from "core/utils"
|
||||
//import "less/json-schema-form"
|
||||
|
||||
const noop = ()=> {}
|
||||
@@ -15,6 +17,7 @@ const JsonSchemaPropShape = {
|
||||
schema: PropTypes.object,
|
||||
errors: ImPropTypes.list,
|
||||
required: PropTypes.bool,
|
||||
dispatchInitialValue: PropTypes.bool,
|
||||
description: PropTypes.any
|
||||
}
|
||||
|
||||
@@ -32,6 +35,13 @@ export class JsonSchemaForm extends Component {
|
||||
static propTypes = JsonSchemaPropShape
|
||||
static defaultProps = JsonSchemaDefaultProps
|
||||
|
||||
componentDidMount() {
|
||||
const { dispatchInitialValue, value, onChange } = this.props
|
||||
if(dispatchInitialValue) {
|
||||
onChange(value)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let { schema, errors, value, onChange, getComponent, fn } = this.props
|
||||
|
||||
@@ -101,7 +111,7 @@ export class JsonSchema_array extends PureComponent {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {value: props.value}
|
||||
this.state = { value: valueOrEmptyList(props.value)}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
@@ -125,7 +135,7 @@ export class JsonSchema_array extends PureComponent {
|
||||
|
||||
addItem = () => {
|
||||
this.setState(state => {
|
||||
state.value = state.value || List()
|
||||
state.value = valueOrEmptyList(state.value)
|
||||
return {
|
||||
value: state.value.push("")
|
||||
}
|
||||
@@ -164,7 +174,7 @@ export class JsonSchema_array extends PureComponent {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ !value || value.count() < 1 ? null :
|
||||
{ !value || !value.count || value.count() < 1 ? null :
|
||||
value.map( (item,i) => {
|
||||
let schema = Object.assign({}, itemSchema)
|
||||
if ( errors.length ) {
|
||||
@@ -191,7 +201,7 @@ export class JsonSchema_boolean extends Component {
|
||||
|
||||
onEnumChange = (val) => this.props.onChange(val)
|
||||
render() {
|
||||
let { getComponent, value, errors, schema } = this.props
|
||||
let { getComponent, value, errors, schema, required } = this.props
|
||||
errors = errors.toJS ? errors.toJS() : []
|
||||
|
||||
const Select = getComponent("Select")
|
||||
@@ -200,7 +210,61 @@ export class JsonSchema_boolean extends Component {
|
||||
title={ errors.length ? errors : ""}
|
||||
value={ String(value) }
|
||||
allowedValues={ fromJS(schema.enum || ["true", "false"]) }
|
||||
allowEmptyValue={ !this.props.required }
|
||||
allowEmptyValue={ !schema.enum || !required }
|
||||
onChange={ this.onEnumChange }/>)
|
||||
}
|
||||
}
|
||||
|
||||
export class JsonSchema_object extends PureComponent {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
static propTypes = JsonSchemaPropShape
|
||||
static defaultProps = JsonSchemaDefaultProps
|
||||
|
||||
componentDidMount() {
|
||||
if(!this.props.value && this.props.schema) {
|
||||
this.resetValueToSample()
|
||||
}
|
||||
}
|
||||
|
||||
resetValueToSample = () => {
|
||||
this.onChange(getSampleSchema(this.props.schema) )
|
||||
}
|
||||
|
||||
onChange = (value) => {
|
||||
this.props.onChange(value)
|
||||
}
|
||||
|
||||
handleOnChange = e => {
|
||||
const inputValue = e.target.value
|
||||
|
||||
this.onChange(inputValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
getComponent,
|
||||
value,
|
||||
errors
|
||||
} = this.props
|
||||
|
||||
const TextArea = getComponent("TextArea")
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TextArea
|
||||
className={cx({ invalid: errors.size })}
|
||||
title={ errors.size ? errors.join(", ") : ""}
|
||||
value={value}
|
||||
onChange={ this.handleOnChange }/>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function valueOrEmptyList(value) {
|
||||
return List.isList(value) ? value : List()
|
||||
}
|
||||
@@ -18,3 +18,7 @@ export function toggle(configName) {
|
||||
payload: configName,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Hook
|
||||
export const loaded = () => () => {}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
// import reducers from "./reducers"
|
||||
// import * as actions from "./actions"
|
||||
// import * as selectors from "./selectors"
|
||||
import * as specWrapActions from "./spec-wrap-actions"
|
||||
import * as layoutWrapActions from "./layout-wrap-actions"
|
||||
import layout from "./layout"
|
||||
import OperationWrapper from "./operation-wrapper"
|
||||
import OperationTagWrapper from "./operation-tag-wrapper"
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
return [layout, {
|
||||
statePlugins: {
|
||||
spec: {
|
||||
wrapActions: specWrapActions
|
||||
},
|
||||
layout: {
|
||||
wrapActions: layoutWrapActions
|
||||
configs: {
|
||||
wrapActions: {
|
||||
loaded: (ori, system) => (...args) => {
|
||||
ori(...args)
|
||||
const hash = window.location.hash
|
||||
system.layoutActions.parseDeepLinkHash(hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
wrapComponents: {
|
||||
operation: OperationWrapper,
|
||||
OperationTag: OperationTagWrapper,
|
||||
},
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { setHash } from "./helpers"
|
||||
import { createDeepLinkPath } from "core/utils"
|
||||
|
||||
export const show = (ori, { getConfigs }) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let [thing, shown] = args
|
||||
let [type] = thing
|
||||
|
||||
if(type === "operations-tag" || type === "operations") {
|
||||
if(!shown) {
|
||||
return setHash("/")
|
||||
}
|
||||
|
||||
if(type === "operations") {
|
||||
let [, tag, operationId] = thing
|
||||
setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`)
|
||||
}
|
||||
|
||||
if(type === "operations-tag") {
|
||||
let [, tag] = thing
|
||||
setHash(`/${createDeepLinkPath(tag)}`)
|
||||
}
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
// This functionality is not mission critical, so if something goes wrong
|
||||
// we'll just move on
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import { setHash } from "./helpers"
|
||||
import zenscroll from "zenscroll"
|
||||
import Im, { fromJS } from "immutable"
|
||||
|
||||
const SCROLL_TO = "layout_scroll_to"
|
||||
const CLEAR_SCROLL_TO = "layout_clear_scroll"
|
||||
|
||||
export const show = (ori, { getConfigs, layoutSelectors }) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
if(!getConfigs().deepLinking) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let [tokenArray, shown] = args
|
||||
//Coerce in to array
|
||||
tokenArray = Array.isArray(tokenArray) ? tokenArray : [tokenArray]
|
||||
// Convert into something we can put in the URL hash
|
||||
// Or return empty, if we cannot
|
||||
const urlHashArray = layoutSelectors.urlHashArrayFromIsShownKey(tokenArray) // Will convert
|
||||
|
||||
// No hash friendly list?
|
||||
if(!urlHashArray.length)
|
||||
return
|
||||
|
||||
const [type, assetName] = urlHashArray
|
||||
|
||||
if (!shown) {
|
||||
return setHash("/")
|
||||
}
|
||||
|
||||
if (urlHashArray.length === 2) {
|
||||
setHash(`/${type}/${assetName}`)
|
||||
} else if (urlHashArray.length === 1) {
|
||||
setHash(`/${type}`)
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
// This functionality is not mission critical, so if something goes wrong
|
||||
// we'll just move on
|
||||
console.error(e) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
export const scrollTo = (path) => {
|
||||
return {
|
||||
type: SCROLL_TO,
|
||||
payload: Array.isArray(path) ? path : [path]
|
||||
}
|
||||
}
|
||||
|
||||
export const parseDeepLinkHash = (rawHash) => ({ layoutActions, layoutSelectors, getConfigs }) => {
|
||||
|
||||
if(!getConfigs().deepLinking) {
|
||||
return
|
||||
}
|
||||
|
||||
if(rawHash) {
|
||||
let hash = rawHash.slice(1) // # is first character
|
||||
|
||||
|
||||
if(hash[0] === "!") {
|
||||
// Parse UI 2.x shebangs
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
if(hash[0] === "/") {
|
||||
// "/pet/addPet" => "pet/addPet"
|
||||
// makes the split result cleaner
|
||||
// also handles forgotten leading slash
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
const isShownKey = layoutSelectors.isShownKeyFromUrlHashArray(hash.split("/"))
|
||||
|
||||
layoutActions.show(isShownKey, true) // TODO: 'show' operation tag
|
||||
layoutActions.scrollTo(isShownKey)
|
||||
}
|
||||
}
|
||||
|
||||
export const readyToScroll = (isShownKey, ref) => (system) => {
|
||||
const scrollToKey = system.layoutSelectors.getScrollToKey()
|
||||
|
||||
if(Im.is(scrollToKey, fromJS(isShownKey))) {
|
||||
system.layoutActions.scrollToElement(ref)
|
||||
system.layoutActions.clearScrollTo()
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to "ref" (dom node) with the scrollbar on "container" or the nearest parent
|
||||
export const scrollToElement = (ref, container) => (system) => {
|
||||
try {
|
||||
container = container || system.fn.getScrollParent(ref)
|
||||
let myScroller = zenscroll.createScroller(container)
|
||||
myScroller.to(ref)
|
||||
} catch(e) {
|
||||
console.error(e) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
export const clearScrollTo = () => {
|
||||
return {
|
||||
type: CLEAR_SCROLL_TO,
|
||||
}
|
||||
}
|
||||
|
||||
// From: https://stackoverflow.com/a/42543908/3933724
|
||||
// Modified to return html instead of body element as last resort
|
||||
function getScrollParent(element, includeHidden) {
|
||||
const LAST_RESORT = document.documentElement
|
||||
let style = getComputedStyle(element)
|
||||
const excludeStaticParent = style.position === "absolute"
|
||||
const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/
|
||||
|
||||
if (style.position === "fixed")
|
||||
return LAST_RESORT
|
||||
for (let parent = element; (parent = parent.parentElement);) {
|
||||
style = getComputedStyle(parent)
|
||||
if (excludeStaticParent && style.position === "static") {
|
||||
continue
|
||||
}
|
||||
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX))
|
||||
return parent
|
||||
}
|
||||
|
||||
return LAST_RESORT
|
||||
}
|
||||
|
||||
export default {
|
||||
fn: {
|
||||
getScrollParent,
|
||||
},
|
||||
statePlugins: {
|
||||
layout: {
|
||||
actions: {
|
||||
scrollToElement,
|
||||
scrollTo,
|
||||
clearScrollTo,
|
||||
readyToScroll,
|
||||
parseDeepLinkHash
|
||||
},
|
||||
selectors: {
|
||||
getScrollToKey(state) {
|
||||
return state.get("scrollToKey")
|
||||
},
|
||||
isShownKeyFromUrlHashArray(state, urlHashArray) {
|
||||
const [tag, operationId] = urlHashArray
|
||||
// We only put operations in the URL
|
||||
if(operationId) {
|
||||
return ["operations", tag, operationId]
|
||||
} else if (tag) {
|
||||
return ["operations-tag", tag]
|
||||
}
|
||||
return []
|
||||
},
|
||||
urlHashArrayFromIsShownKey(state, isShownKey) {
|
||||
let [type, tag, operationId] = isShownKey
|
||||
// We only put operations in the URL
|
||||
if(type == "operations") {
|
||||
return [tag, operationId]
|
||||
} else if (type == "operations-tag") {
|
||||
return [tag]
|
||||
}
|
||||
return []
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
[SCROLL_TO](state, action) {
|
||||
return state.set("scrollToKey", Im.fromJS(action.payload))
|
||||
},
|
||||
[CLEAR_SCROLL_TO](state) {
|
||||
return state.delete("scrollToKey")
|
||||
}
|
||||
},
|
||||
wrapActions: {
|
||||
show
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from "react"
|
||||
import { PropTypes } from "prop-types"
|
||||
|
||||
const Wrapper = (Ori, system) => class OperationTagWrapper extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
tag: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
onLoad = (ref) => {
|
||||
const { tag } = this.props
|
||||
const isShownKey = ["operations-tag", tag]
|
||||
system.layoutActions.readyToScroll(isShownKey, ref)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span ref={this.onLoad}>
|
||||
<Ori {...this.props} />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Wrapper
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from "react"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
|
||||
const Wrapper = (Ori, system) => class OperationWrapper extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
operation: ImPropTypes.map.isRequired,
|
||||
}
|
||||
|
||||
onLoad = (ref) => {
|
||||
const { operation } = this.props
|
||||
const { tag, operationId } = operation.toObject()
|
||||
const isShownKey = ["operations", tag, operationId]
|
||||
system.layoutActions.readyToScroll(isShownKey, ref)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span ref={this.onLoad}>
|
||||
<Ori {...this.props} />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Wrapper
|
||||
@@ -1,64 +0,0 @@
|
||||
import zenscroll from "zenscroll"
|
||||
import { escapeDeepLinkPath } from "core/utils"
|
||||
|
||||
let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed
|
||||
|
||||
|
||||
export const updateJsonSpec = (ori, { layoutActions, getConfigs }) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
||||
return
|
||||
}
|
||||
if(window.location.hash && !hasHashBeenParsed ) {
|
||||
let hash = window.location.hash.slice(1) // # is first character
|
||||
|
||||
if(hash[0] === "!") {
|
||||
// Parse UI 2.x shebangs
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
if(hash[0] === "/") {
|
||||
// "/pet/addPet" => "pet/addPet"
|
||||
// makes the split result cleaner
|
||||
// also handles forgotten leading slash
|
||||
hash = hash.slice(1)
|
||||
}
|
||||
|
||||
let [tag, operationId] = hash.split("/")
|
||||
|
||||
let swaggerUI = document.querySelector(".swagger-ui")
|
||||
let myScroller = zenscroll.createScroller(swaggerUI)
|
||||
|
||||
let target
|
||||
|
||||
if(tag && operationId) {
|
||||
// Pre-expand and scroll to the operation
|
||||
layoutActions.show(["operations-tag", tag], true)
|
||||
layoutActions.show(["operations", tag, operationId], true)
|
||||
|
||||
target = document
|
||||
.getElementById(`operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`)
|
||||
} else if(tag) {
|
||||
// Pre-expand and scroll to the tag
|
||||
layoutActions.show(["operations-tag", tag], true)
|
||||
|
||||
target = document.getElementById(`operations-tag-${escapeDeepLinkPath(tag)}`)
|
||||
}
|
||||
|
||||
|
||||
if(target) {
|
||||
myScroller.to(target)
|
||||
setTimeout(() => {
|
||||
// Backup functionality: if we're still at the top of the document,
|
||||
// scroll on the entire page (not within the Swagger-UI container)
|
||||
if(zenscroll.getY() === 0) {
|
||||
zenscroll.to(target)
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
hasHashBeenParsed = true
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import Callbacks from "./callbacks"
|
||||
import RequestBody from "./request-body"
|
||||
import OperationLink from "./operation-link.jsx"
|
||||
import Servers from "./servers"
|
||||
import ServersContainer from "./servers-container"
|
||||
import RequestBodyEditor from "./request-body-editor"
|
||||
import HttpAuth from "./http-auth"
|
||||
import OperationServers from "./operation-servers"
|
||||
@@ -11,6 +12,7 @@ export default {
|
||||
HttpAuth,
|
||||
RequestBody,
|
||||
Servers,
|
||||
ServersContainer,
|
||||
RequestBodyEditor,
|
||||
OperationServers,
|
||||
operationLink: OperationLink
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import ImPropTypes from "react-immutable-proptypes"
|
||||
import { OrderedMap } from "immutable"
|
||||
import { getSampleSchema } from "core/utils"
|
||||
import { Map, OrderedMap } from "immutable"
|
||||
|
||||
const RequestBody = ({
|
||||
requestBody,
|
||||
requestBodyValue,
|
||||
getComponent,
|
||||
getConfigs,
|
||||
specSelectors,
|
||||
fn,
|
||||
contentType,
|
||||
isExecute,
|
||||
specPath,
|
||||
onChange
|
||||
}) => {
|
||||
const handleFile = (e) => {
|
||||
onChange(e.target.files[0])
|
||||
}
|
||||
|
||||
const Markdown = getComponent("Markdown")
|
||||
const ModelExample = getComponent("modelExample")
|
||||
const RequestBodyEditor = getComponent("RequestBodyEditor")
|
||||
@@ -23,10 +30,81 @@ const RequestBody = ({
|
||||
|
||||
const mediaTypeValue = requestBodyContent.get(contentType)
|
||||
|
||||
const isObjectContent = mediaTypeValue.getIn(["schema", "type"]) === "object"
|
||||
|
||||
if(!mediaTypeValue) {
|
||||
return null
|
||||
}
|
||||
|
||||
if(contentType === "application/octet-stream") {
|
||||
const Input = getComponent("Input")
|
||||
|
||||
if(!isExecute) {
|
||||
return <i>
|
||||
Example values are not available for <code>application/octet-stream</code> media types.
|
||||
</i>
|
||||
}
|
||||
|
||||
return <Input type={"file"} onChange={handleFile} />
|
||||
}
|
||||
|
||||
if(
|
||||
isObjectContent &&
|
||||
(contentType === "application/x-www-form-urlencoded"
|
||||
|| contentType.indexOf("multipart/") === 0))
|
||||
{
|
||||
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
||||
const HighlightCode = getComponent("highlightCode")
|
||||
const bodyProperties = requestBody.getIn(["content", contentType, "schema", "properties"], OrderedMap())
|
||||
requestBodyValue = Map.isMap(requestBodyValue) ? requestBodyValue : OrderedMap()
|
||||
|
||||
return <div className="table-container">
|
||||
<table>
|
||||
<tbody>
|
||||
{
|
||||
bodyProperties.map((prop, key) => {
|
||||
const required = prop.get("required")
|
||||
const type = prop.get("type")
|
||||
const format = prop.get("format")
|
||||
|
||||
const isFile = type === "string" && (format === "binary" || format === "base64")
|
||||
|
||||
return <tr key={key} className="parameters">
|
||||
<td className="col parameters-col_name">
|
||||
<div className={required ? "parameter__name required" : "parameter__name"}>
|
||||
{ key }
|
||||
{ !required ? null : <span style={{color: "red"}}> *</span> }
|
||||
</div>
|
||||
<div className="parameter__type">
|
||||
{ type }
|
||||
{ format && <span className="prop-format">(${format})</span>}
|
||||
</div>
|
||||
<div className="parameter__deprecated">
|
||||
{ prop.get("deprecated") ? "deprecated": null }
|
||||
</div>
|
||||
</td>
|
||||
<td className="col parameters-col_description">
|
||||
{isExecute ?
|
||||
<JsonSchemaForm
|
||||
fn={fn}
|
||||
dispatchInitialValue={!isFile}
|
||||
schema={prop}
|
||||
getComponent={getComponent}
|
||||
value={requestBodyValue.get(key) || getSampleSchema(prop)}
|
||||
onChange={(value) => {
|
||||
onChange(value, [key])
|
||||
}}
|
||||
/>
|
||||
: <HighlightCode className="example" value={ getSampleSchema(prop) } />}
|
||||
</td>
|
||||
</tr>
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
|
||||
return <div>
|
||||
{ requestBodyDescription &&
|
||||
<Markdown source={requestBodyDescription} />
|
||||
@@ -53,8 +131,10 @@ const RequestBody = ({
|
||||
|
||||
RequestBody.propTypes = {
|
||||
requestBody: ImPropTypes.orderedMap.isRequired,
|
||||
requestBodyValue: ImPropTypes.orderedMap.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
fn: PropTypes.object.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
contentType: PropTypes.string,
|
||||
isExecute: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
export default class ServersContainer extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
oas3Selectors: PropTypes.object.isRequired,
|
||||
oas3Actions: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render () {
|
||||
const {specSelectors, oas3Selectors, oas3Actions, getComponent} = this.props
|
||||
|
||||
const servers = specSelectors.servers()
|
||||
|
||||
const Col = getComponent("Col")
|
||||
const Servers = getComponent("Servers")
|
||||
|
||||
return (
|
||||
<div>
|
||||
{servers && servers.size ? (
|
||||
<div className="global-server-container">
|
||||
<Col className="servers wrapper" mobile={12}>
|
||||
<span className="servers-title">Server</span>
|
||||
<Servers
|
||||
servers={servers}
|
||||
currentServer={oas3Selectors.selectedServer()}
|
||||
setSelectedServer={oas3Actions.setSelectedServer}
|
||||
setServerVariableValue={oas3Actions.setServerVariableValue}
|
||||
getServerVariable={oas3Selectors.serverVariableValue}
|
||||
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
|
||||
/>
|
||||
</Col>
|
||||
</div>
|
||||
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,24 @@ import React from "react"
|
||||
|
||||
export function isOAS3(jsSpec) {
|
||||
const oasVersion = jsSpec.get("openapi")
|
||||
if(!oasVersion) {
|
||||
if(typeof oasVersion !== "string") {
|
||||
return false
|
||||
}
|
||||
|
||||
return oasVersion.startsWith("3")
|
||||
// we gate against `3.1` becasue we want to explicitly opt into supporting it
|
||||
// at some point in the future -- KS, 7/2018
|
||||
|
||||
// starts with, but is not `3.0.` exactly
|
||||
return oasVersion.startsWith("3.0.") && oasVersion.length > 4
|
||||
}
|
||||
|
||||
export function isSwagger2(jsSpec) {
|
||||
const swaggerVersion = jsSpec.get("swagger")
|
||||
if(!swaggerVersion) {
|
||||
if(typeof swaggerVersion !== "string") {
|
||||
return false
|
||||
}
|
||||
|
||||
return swaggerVersion.startsWith("2")
|
||||
return swaggerVersion.startsWith("2.0")
|
||||
}
|
||||
|
||||
export function OAS3ComponentWrapFactory(Component) {
|
||||
|
||||
@@ -4,11 +4,13 @@ import parameters from "./parameters"
|
||||
import VersionStamp from "./version-stamp"
|
||||
import OnlineValidatorBadge from "./online-validator-badge"
|
||||
import Model from "./model"
|
||||
import JsonSchema_string from "./json-schema-string"
|
||||
|
||||
export default {
|
||||
Markdown,
|
||||
AuthItem,
|
||||
parameters,
|
||||
JsonSchema_string,
|
||||
VersionStamp,
|
||||
model: Model,
|
||||
onlineValidatorBadge: OnlineValidatorBadge,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from "react"
|
||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||
|
||||
export default OAS3ComponentWrapFactory(({ Ori, ...props }) => {
|
||||
const {
|
||||
schema,
|
||||
getComponent,
|
||||
errors,
|
||||
onChange
|
||||
} = props
|
||||
|
||||
const { type, format } = schema
|
||||
const Input = getComponent("Input")
|
||||
|
||||
if(type === "string" && (format === "binary" || format === "base64")) {
|
||||
return <Input type="file"
|
||||
className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.files[0])
|
||||
}}
|
||||
disabled={Ori.isDisabled}/>
|
||||
} else {
|
||||
return <Ori {...props} />
|
||||
}
|
||||
})
|
||||
@@ -47,11 +47,11 @@ class Parameters extends Component {
|
||||
|
||||
onChange = ( param, value, isXml ) => {
|
||||
let {
|
||||
specActions: { changeParam },
|
||||
specActions: { changeParamByIdentity },
|
||||
onChangeKey,
|
||||
} = this.props
|
||||
|
||||
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
|
||||
changeParamByIdentity( onChangeKey, param, value, isXml)
|
||||
}
|
||||
|
||||
onChangeConsumesWrapper = ( val ) => {
|
||||
@@ -145,7 +145,8 @@ class Parameters extends Component {
|
||||
getComponent={ getComponent }
|
||||
specPath={specPath.push(i)}
|
||||
getConfigs={ getConfigs }
|
||||
param={ parameter }
|
||||
rawParam={ parameter }
|
||||
param={ specSelectors.parameterWithMetaByIdentity(pathMethod, parameter) }
|
||||
key={ parameter.get( "name" ) }
|
||||
onChange={ this.onChange }
|
||||
onChangeConsumes={this.onChangeConsumesWrapper}
|
||||
@@ -185,8 +186,17 @@ class Parameters extends Component {
|
||||
<RequestBody
|
||||
specPath={requestBodySpecPath}
|
||||
requestBody={requestBody}
|
||||
requestBodyValue={oas3Selectors.requestBodyValue(...pathMethod) || Map()}
|
||||
isExecute={isExecute}
|
||||
onChange={(value) => {
|
||||
onChange={(value, path) => {
|
||||
if(path) {
|
||||
const lastValue = oas3Selectors.requestBodyValue(...pathMethod)
|
||||
const usableValue = Map.isMap(lastValue) ? lastValue : Map()
|
||||
return oas3Actions.setRequestBodyValue({
|
||||
pathMethod,
|
||||
value: usableValue.setIn(path, value)
|
||||
})
|
||||
}
|
||||
oas3Actions.setRequestBodyValue({ value, pathMethod })
|
||||
}}
|
||||
contentType={oas3Selectors.requestContentType(...pathMethod)}/>
|
||||
|
||||
@@ -29,6 +29,7 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
let { type, example, properties, additionalProperties, items } = objectify(schema)
|
||||
let { includeReadOnly, includeWriteOnly } = config
|
||||
|
||||
|
||||
if(example !== undefined) {
|
||||
return deeplyStripKey(example, "$$ref", (val) => {
|
||||
// do a couple of quick sanity tests to ensure the value
|
||||
|
||||
@@ -234,6 +234,13 @@ export function changeParam( path, paramName, paramIn, value, isXml ){
|
||||
}
|
||||
}
|
||||
|
||||
export function changeParamByIdentity( pathMethod, param, value, isXml ){
|
||||
return {
|
||||
type: UPDATE_PARAM,
|
||||
payload:{ path: pathMethod, param, value, isXml }
|
||||
}
|
||||
}
|
||||
|
||||
export const updateResolvedSubtree = (path, value) => {
|
||||
return {
|
||||
type: UPDATE_RESOLVED_SUBTREE,
|
||||
@@ -348,7 +355,9 @@ export const executeRequest = (req) =>
|
||||
|
||||
if(isJSONObject(requestBody)) {
|
||||
req.requestBody = JSON.parse(requestBody)
|
||||
} else {
|
||||
} else if(requestBody && requestBody.toJS) {
|
||||
req.requestBody = requestBody.toJS()
|
||||
} else{
|
||||
req.requestBody = requestBody
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +51,21 @@ export default {
|
||||
},
|
||||
|
||||
[UPDATE_PARAM]: ( state, {payload} ) => {
|
||||
let { path: pathMethod, paramName, paramIn, value, isXml } = payload
|
||||
let { path: pathMethod, paramName, paramIn, param, value, isXml } = payload
|
||||
|
||||
let paramKey
|
||||
|
||||
// `hashCode` is an Immutable.js Map method
|
||||
if(param && param.hashCode && !paramIn && !paramName) {
|
||||
paramKey = `${param.get("name")}.${param.get("in")}.hash-${param.hashCode()}`
|
||||
} else {
|
||||
paramKey = `${paramName}.${paramIn}`
|
||||
}
|
||||
|
||||
const valueKey = isXml ? "value_xml" : "value"
|
||||
|
||||
return state.setIn(
|
||||
["meta", "paths", ...pathMethod, "parameters", `${paramName}.${paramIn}`, valueKey],
|
||||
["meta", "paths", ...pathMethod, "parameters", paramKey, valueKey],
|
||||
value
|
||||
)
|
||||
},
|
||||
|
||||
@@ -294,34 +294,42 @@ export const allowTryItOutFor = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const operationWithMeta = (state, path, method) => {
|
||||
const op = specJsonWithResolvedSubtrees(state).getIn(["paths", path, method], Map())
|
||||
const meta = state.getIn(["meta", "paths", path, method], Map())
|
||||
export const parameterWithMetaByIdentity = (state, pathMethod, param) => {
|
||||
const opParams = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "parameters"], OrderedMap())
|
||||
const metaParams = state.getIn(["meta", "paths", ...pathMethod, "parameters"], OrderedMap())
|
||||
|
||||
const mergedParams = op.get("parameters", List()).map((param) => {
|
||||
return Map().merge(
|
||||
param,
|
||||
meta.getIn(["parameters", `${param.get("name")}.${param.get("in")}`])
|
||||
const mergedParams = opParams.map((currentParam) => {
|
||||
const nameInKeyedMeta = metaParams.get(`${param.get("name")}.${param.get("in")}`)
|
||||
const hashKeyedMeta = metaParams.get(`${param.get("name")}.${param.get("in")}.hash-${param.hashCode()}`)
|
||||
return OrderedMap().merge(
|
||||
currentParam,
|
||||
nameInKeyedMeta,
|
||||
hashKeyedMeta
|
||||
)
|
||||
})
|
||||
|
||||
return Map()
|
||||
.merge(op, meta)
|
||||
.set("parameters", mergedParams)
|
||||
return mergedParams.find(curr => curr.get("in") === param.get("in") && curr.get("name") === param.get("name"), OrderedMap())
|
||||
}
|
||||
|
||||
export const parameterWithMeta = (state, pathMethod, paramName, paramIn) => {
|
||||
const opParams = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "parameters"], Map())
|
||||
const metaParams = state.getIn(["meta", "paths", ...pathMethod, "parameters"], Map())
|
||||
|
||||
const mergedParams = opParams.map((param) => {
|
||||
return Map().merge(
|
||||
param,
|
||||
metaParams.get(`${param.get("name")}.${param.get("in")}`)
|
||||
)
|
||||
export const parameterWithMeta = (state, pathMethod, paramName, paramIn) => {
|
||||
const opParams = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "parameters"], OrderedMap())
|
||||
const currentParam = opParams.find(param => param.get("in") === paramIn && param.get("name") === paramName, OrderedMap())
|
||||
|
||||
return parameterWithMetaByIdentity(state, pathMethod, currentParam)
|
||||
}
|
||||
|
||||
export const operationWithMeta = (state, path, method) => {
|
||||
const op = specJsonWithResolvedSubtrees(state).getIn(["paths", path, method], OrderedMap())
|
||||
const meta = state.getIn(["meta", "paths", path, method], OrderedMap())
|
||||
|
||||
const mergedParams = op.get("parameters", List()).map((param) => {
|
||||
return parameterWithMetaByIdentity(state, [path, method], param)
|
||||
})
|
||||
|
||||
return mergedParams.find(param => param.get("in") === paramIn && param.get("name") === paramName, Map())
|
||||
return OrderedMap()
|
||||
.merge(op, meta)
|
||||
.set("parameters", mergedParams)
|
||||
}
|
||||
|
||||
// Get the parameter value by parameter name
|
||||
|
||||
@@ -31,6 +31,7 @@ import Clear from "core/components/clear"
|
||||
import LiveResponse from "core/components/live-response"
|
||||
import OnlineValidatorBadge from "core/components/online-validator-badge"
|
||||
import Operations from "core/components/operations"
|
||||
import OperationTag from "core/components/operation-tag"
|
||||
import Operation from "core/components/operation"
|
||||
import OperationExt from "core/components/operation-extensions"
|
||||
import OperationExtRow from "core/components/operation-extension-row"
|
||||
@@ -50,10 +51,13 @@ import Info, {
|
||||
InfoUrl,
|
||||
InfoBasePath
|
||||
} from "core/components/info"
|
||||
import InfoContainer from "core/containers/info"
|
||||
import Footer from "core/components/footer"
|
||||
import FilterContainer from "core/containers/filter"
|
||||
import ParamBody from "core/components/param-body"
|
||||
import Curl from "core/components/curl"
|
||||
import Schemes from "core/components/schemes"
|
||||
import SchemesContainer from "core/containers/schemes"
|
||||
import ModelCollapse from "core/components/model-collapse"
|
||||
import ModelExample from "core/components/model-example"
|
||||
import ModelWrapper from "core/components/model-wrapper"
|
||||
@@ -65,6 +69,7 @@ import ArrayModel from "core/components/array-model"
|
||||
import PrimitiveModel from "core/components/primitive-model"
|
||||
import Property from "core/components/property"
|
||||
import TryItOutButton from "core/components/try-it-out-button"
|
||||
import VersionPragmaFilter from "core/components/version-pragma-filter"
|
||||
import VersionStamp from "core/components/version-stamp"
|
||||
import DeepLink from "core/components/deep-link"
|
||||
import SvgAssets from "core/components/svg-assets"
|
||||
@@ -93,6 +98,7 @@ export default function() {
|
||||
clear: Clear,
|
||||
liveResponse: LiveResponse,
|
||||
info: Info,
|
||||
InfoContainer,
|
||||
onlineValidatorBadge: OnlineValidatorBadge,
|
||||
operations: Operations,
|
||||
operation: Operation,
|
||||
@@ -108,9 +114,11 @@ export default function() {
|
||||
contentType: ContentType,
|
||||
overview: Overview,
|
||||
footer: Footer,
|
||||
FilterContainer,
|
||||
ParamBody: ParamBody,
|
||||
curl: Curl,
|
||||
schemes: Schemes,
|
||||
SchemesContainer,
|
||||
modelExample: ModelExample,
|
||||
ModelWrapper,
|
||||
ModelCollapse,
|
||||
@@ -124,10 +132,12 @@ export default function() {
|
||||
TryItOutButton,
|
||||
Markdown,
|
||||
BaseLayout,
|
||||
VersionPragmaFilter,
|
||||
VersionStamp,
|
||||
OperationExt,
|
||||
OperationExtRow,
|
||||
ParameterExt,
|
||||
OperationTag,
|
||||
OperationContainer,
|
||||
DeepLink,
|
||||
InfoUrl,
|
||||
|
||||
+26
-3
@@ -37,7 +37,7 @@ export function objectify (thing) {
|
||||
if(!isObject(thing))
|
||||
return {}
|
||||
if(isImmutable(thing))
|
||||
return thing.toObject()
|
||||
return thing.toJS()
|
||||
return thing
|
||||
}
|
||||
|
||||
@@ -503,7 +503,30 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
|
||||
let numberCheck = type === "number" && (value || value === 0)
|
||||
let integerCheck = type === "integer" && (value || value === 0)
|
||||
|
||||
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
||||
let oas3ObjectCheck = false
|
||||
|
||||
if(false || isOAS3 && type === "object") {
|
||||
if(typeof value === "object") {
|
||||
oas3ObjectCheck = true
|
||||
} else if(typeof value === "string") {
|
||||
try {
|
||||
JSON.parse(value)
|
||||
oas3ObjectCheck = true
|
||||
} catch(e) {
|
||||
errors.push("Parameter string value must be valid JSON")
|
||||
return errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allChecks = [
|
||||
stringCheck, arrayCheck, listCheck, fileCheck, booleanCheck,
|
||||
numberCheck, integerCheck, oas3ObjectCheck
|
||||
]
|
||||
|
||||
const passedAnyCheck = allChecks.some(v => !!v)
|
||||
|
||||
if ( required && !passedAnyCheck ) {
|
||||
errors.push("Required field is not provided")
|
||||
return errors
|
||||
}
|
||||
@@ -719,7 +742,7 @@ export const getCommonExtensions = (defObj) => defObj.filter((v, k) => /^pattern
|
||||
// `predicate` can be used to discriminate the stripping further,
|
||||
// by preserving the key's place in the object based on its value.
|
||||
export function deeplyStripKey(input, keyToStrip, predicate = () => true) {
|
||||
if(typeof input !== "object" || Array.isArray(input) || !keyToStrip) {
|
||||
if(typeof input !== "object" || Array.isArray(input) || input === null || !keyToStrip) {
|
||||
return input
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Here is an example of each `type`
|
||||
```js
|
||||
// A contrived, but quite full example....
|
||||
|
||||
export function SomePlugin( toolbox ) {
|
||||
export function SomePlugin(toolbox) {
|
||||
|
||||
const UPDATE_SOMETHING = "some_namespace_update_something" // strings just need to be uniuqe... see below
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ export default class Topbar extends React.Component {
|
||||
<div className="topbar">
|
||||
<div className="wrapper">
|
||||
<div className="topbar-wrapper">
|
||||
<Link href="#">
|
||||
<Link>
|
||||
<img height="30" width="30" src={ Logo } alt="Swagger UI"/>
|
||||
<span>swagger</span>
|
||||
</Link>
|
||||
|
||||
@@ -51,7 +51,8 @@ input[type=text],
|
||||
input[type=password],
|
||||
input[type=search],
|
||||
input[type=email],
|
||||
input[type=file]
|
||||
input[type=file],
|
||||
textarea
|
||||
{
|
||||
min-width: 100px;
|
||||
margin: 5px 0;
|
||||
|
||||
@@ -796,3 +796,30 @@ a.nostyle {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.version-pragma {
|
||||
height: 100%;
|
||||
padding: 5em 0px;
|
||||
|
||||
&__message {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
line-height: 1.5em;
|
||||
|
||||
padding: 0px .6em;
|
||||
|
||||
> div {
|
||||
max-width: 55ch;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #dedede;
|
||||
padding: 4px 4px 2px;
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ section.models
|
||||
.model-container
|
||||
{
|
||||
margin: 0 20px 15px;
|
||||
position: relative;
|
||||
|
||||
transition: all .5s;
|
||||
|
||||
@@ -186,6 +187,13 @@ section.models
|
||||
{
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.models-jump-to-path {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 5px;
|
||||
opacity: 0.65;
|
||||
}
|
||||
}
|
||||
|
||||
.model-box
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@mixin text_body($color: $text-body-default-font-color)
|
||||
{
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-family: sans-serif;
|
||||
|
||||
color: $color;
|
||||
}
|
||||
|
||||
@mixin text_code($color: $text-code-default-font-color)
|
||||
{
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
|
||||
color: $color;
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
@mixin text_headline($color: $text-headline-default-font-color)
|
||||
{
|
||||
font-family: 'Titillium Web', sans-serif;
|
||||
font-family: sans-serif;
|
||||
|
||||
color: $color;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
url: "http://petstore.swagger.io/v2/swagger.json"
|
||||
url: "https://petstore.swagger.io/v2/swagger.json"
|
||||
dom_id: "#swagger-ui"
|
||||
validatorUrl: "https://online.swagger.io/validator"
|
||||
oauth2RedirectUrl: "http://localhost:3200/oauth2-redirect.html"
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import { List, fromJS } from "immutable"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { render } from "enzyme"
|
||||
import ParameterRow from "components/parameter-row"
|
||||
|
||||
describe("bug #4557: default parameter values", function(){
|
||||
it("should apply a Swagger 2.0 default value", function(){
|
||||
|
||||
const paramValue = fromJS({
|
||||
description: "a pet",
|
||||
type: "string",
|
||||
default: "MyDefaultValue"
|
||||
})
|
||||
|
||||
let props = {
|
||||
getComponent: ()=> "div",
|
||||
specSelectors: {
|
||||
security(){},
|
||||
parameterWithMetaByIdentity(){ return paramValue },
|
||||
isOAS3(){ return false }
|
||||
},
|
||||
fn: {},
|
||||
operation: {get: ()=>{}},
|
||||
onChange: createSpy(),
|
||||
param: paramValue,
|
||||
rawParam: paramValue,
|
||||
onChangeConsumes: () => {},
|
||||
pathMethod: [],
|
||||
getConfigs: () => { return {} },
|
||||
specPath: List([])
|
||||
}
|
||||
|
||||
render(<ParameterRow {...props}/>)
|
||||
|
||||
expect(props.onChange).toHaveBeenCalled()
|
||||
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue", false)
|
||||
})
|
||||
it("should apply an OpenAPI 3.0 default value", function(){
|
||||
|
||||
const paramValue = fromJS({
|
||||
description: "a pet",
|
||||
schema: {
|
||||
type: "string",
|
||||
default: "MyDefaultValue"
|
||||
}
|
||||
})
|
||||
|
||||
let props = {
|
||||
getComponent: ()=> "div",
|
||||
specSelectors: {
|
||||
security(){},
|
||||
parameterWithMetaByIdentity(){ return paramValue },
|
||||
isOAS3(){ return true }
|
||||
},
|
||||
fn: {},
|
||||
operation: {get: ()=>{}},
|
||||
onChange: createSpy(),
|
||||
param: paramValue,
|
||||
rawParam: paramValue,
|
||||
onChangeConsumes: () => {},
|
||||
pathMethod: [],
|
||||
getConfigs: () => { return {} },
|
||||
specPath: List([])
|
||||
}
|
||||
|
||||
render(<ParameterRow {...props}/>)
|
||||
|
||||
expect(props.onChange).toHaveBeenCalled()
|
||||
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue", false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { mount } from "enzyme"
|
||||
import FilterContainer from "containers/filter"
|
||||
import { Col } from "components/layout-utils"
|
||||
|
||||
describe("<FilterContainer/>", function(){
|
||||
|
||||
const mockedProps = {
|
||||
specSelectors: {
|
||||
loadingStatus() {}
|
||||
},
|
||||
layoutSelectors: {
|
||||
currentFilter() {}
|
||||
},
|
||||
getComponent: () => {return Col}
|
||||
}
|
||||
|
||||
it("renders FilterContainer if filter is provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.layoutSelectors = {...mockedProps.specSelectors}
|
||||
props.layoutSelectors.currentFilter = function() {return true}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<FilterContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedColInsideFilter = wrapper.find(Col)
|
||||
expect(renderedColInsideFilter.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("does not render FilterContainer if filter is null", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.layoutSelectors = {...mockedProps.specSelectors}
|
||||
props.layoutSelectors.currentFilter = function() {return null}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<FilterContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedColInsideFilter = wrapper.find(Col)
|
||||
expect(renderedColInsideFilter.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("does not render FilterContainer if filter is false", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.layoutSelectors = {...mockedProps.specSelectors}
|
||||
props.layoutSelectors.currentFilter = function() {return false}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<FilterContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedColInsideFilter = wrapper.find(Col)
|
||||
expect(renderedColInsideFilter.length).toEqual(0)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { mount } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import InfoContainer from "containers/info"
|
||||
|
||||
describe("<InfoContainer/>", function () {
|
||||
|
||||
const components = {
|
||||
info: () => <span className="mocked-info"/>
|
||||
}
|
||||
const mockedProps = {
|
||||
specSelectors: {
|
||||
info () {},
|
||||
url () {},
|
||||
basePath () {},
|
||||
host () {},
|
||||
externalDocs () {}
|
||||
},
|
||||
getComponent: c => components[c]
|
||||
}
|
||||
|
||||
it("renders Info inside InfoContainer if info is provided", function () {
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.info = function () {return fromJS(["info1", "info2"])}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<InfoContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedInfo = wrapper.find("span.mocked-info")
|
||||
expect(renderedInfo.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("does not render Info inside InfoContainer if no info is provided", function () {
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.info = function () {return fromJS([])}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<InfoContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedInfo = wrapper.find("span.mocked-info")
|
||||
expect(renderedInfo.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("does not render Info inside InfoContainer if info is undefined", function () {
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<InfoContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedInfo = wrapper.find("span.mocked-info")
|
||||
expect(renderedInfo.length).toEqual(0)
|
||||
})
|
||||
})
|
||||
@@ -1,12 +1,13 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import { List } from "immutable"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { Select, Input } from "components/layout-utils"
|
||||
import { render } from "enzyme"
|
||||
import { Select, Input, TextArea } from "components/layout-utils"
|
||||
import { mount, render } from "enzyme"
|
||||
import * as JsonSchemaComponents from "core/json-schema-components"
|
||||
import { JsonSchemaForm } from "core/json-schema-components"
|
||||
|
||||
const components = {...JsonSchemaComponents, Select, Input}
|
||||
const components = {...JsonSchemaComponents, Select, Input, TextArea}
|
||||
|
||||
const getComponentStub = (name) => {
|
||||
if(components[name]) return components[name]
|
||||
@@ -85,6 +86,54 @@ describe("<JsonSchemaForm/>", function(){
|
||||
expect(wrapper.find("select option").eq(2).text()).toEqual("false")
|
||||
})
|
||||
|
||||
|
||||
it("should render the correct options for an enum boolean parameter", function(){
|
||||
|
||||
let props = {
|
||||
getComponent: getComponentStub,
|
||||
value: "",
|
||||
onChange: () => {},
|
||||
keyName: "",
|
||||
fn: {},
|
||||
schema: {
|
||||
type: "boolean",
|
||||
enum: ["true"]
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = render(<JsonSchemaForm {...props}/>)
|
||||
|
||||
expect(wrapper.find("select").length).toEqual(1)
|
||||
expect(wrapper.find("select option").length).toEqual(2)
|
||||
expect(wrapper.find("select option").eq(0).text()).toEqual("--")
|
||||
expect(wrapper.find("select option").eq(1).text()).toEqual("true")
|
||||
expect(wrapper.find("select option:checked").first().text()).toEqual("--")
|
||||
})
|
||||
|
||||
it("should render the correct options for a required boolean parameter", function(){
|
||||
|
||||
let props = {
|
||||
getComponent: getComponentStub,
|
||||
value: "",
|
||||
onChange: () => {},
|
||||
keyName: "",
|
||||
fn: {},
|
||||
schema: {
|
||||
type: "boolean",
|
||||
required: true
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = render(<JsonSchemaForm {...props}/>)
|
||||
|
||||
expect(wrapper.find("select").length).toEqual(1)
|
||||
expect(wrapper.find("select option").length).toEqual(3)
|
||||
expect(wrapper.find("select option").eq(0).text()).toEqual("--")
|
||||
expect(wrapper.find("select option").eq(1).text()).toEqual("true")
|
||||
expect(wrapper.find("select option").eq(2).text()).toEqual("false")
|
||||
expect(wrapper.find("select option:checked").first().text()).toEqual("--")
|
||||
})
|
||||
|
||||
it("should render the correct options for a required enum boolean parameter", function(){
|
||||
|
||||
let props = {
|
||||
@@ -104,7 +153,40 @@ describe("<JsonSchemaForm/>", function(){
|
||||
|
||||
expect(wrapper.find("select").length).toEqual(1)
|
||||
expect(wrapper.find("select option").length).toEqual(1)
|
||||
expect(wrapper.find("select option").first().text()).toEqual("true")
|
||||
expect(wrapper.find("select option").eq(0).text()).toEqual("true")
|
||||
expect(wrapper.find("select option:checked").first().text()).toEqual("true")
|
||||
})
|
||||
})
|
||||
describe("objects", function() {
|
||||
it("should render the correct editor for an OAS3 object parameter", function(){
|
||||
let updateQueue = []
|
||||
|
||||
let props = {
|
||||
getComponent: getComponentStub,
|
||||
value: "",
|
||||
onChange: (value) => {
|
||||
updateQueue.push({ value })
|
||||
},
|
||||
keyName: "",
|
||||
fn: {},
|
||||
errors: List(),
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
example: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let wrapper = mount(<JsonSchemaForm {...props}/>)
|
||||
|
||||
updateQueue.forEach(newProps => wrapper.setProps(newProps))
|
||||
|
||||
expect(wrapper.find("textarea").length).toEqual(1)
|
||||
expect(wrapper.find("textarea").text()).toEqual(`{\n "id": "abc123"\n}`)
|
||||
})
|
||||
})
|
||||
describe("unknown types", function() {
|
||||
|
||||
@@ -16,19 +16,19 @@ describe("Markdown component", function() {
|
||||
it("allows td elements with colspan attrib", function() {
|
||||
const str = `<table><tr><td>ABC</td></tr></table>`
|
||||
const el = render(<Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><table><tr><td>ABC</td></tr></table></div>`)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><table><tbody><tr><td>ABC</td></tr></tbody></table></div>`)
|
||||
})
|
||||
|
||||
it("allows image elements", function() {
|
||||
const str = ``
|
||||
const el = render(<Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><img src="http://image.source" title="Image title"></p>\n</div>`)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><img title="Image title" alt="Image alt text" src="http://image.source"></p>\n</div>`)
|
||||
})
|
||||
|
||||
|
||||
it("allows image elements with https scheme", function() {
|
||||
const str = ``
|
||||
const el = render(<Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><img src="https://image.source" title="Image title"></p>\n</div>`)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><img title="Image title" alt="Image alt text" src="https://image.source"></p>\n</div>`)
|
||||
})
|
||||
|
||||
it("allows image elements with data scheme", function() {
|
||||
@@ -52,7 +52,7 @@ describe("Markdown component", function() {
|
||||
it("allows links", function() {
|
||||
const str = `[Link](https://example.com/)`
|
||||
const el = render(<Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><a href="https://example.com/" target="_blank">Link</a></p>\n</div>`)
|
||||
expect(el.html()).toEqual(`<div class="markdown"><p><a target="_blank" href="https://example.com/">Link</a></p>\n</div>`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -60,13 +60,13 @@ describe("Markdown component", function() {
|
||||
it("allows image elements", function() {
|
||||
const str = ``
|
||||
const el = render(<OAS3Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="http://image.source" title="Image title"></p></div></div>`)
|
||||
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img title="Image title" alt="Image alt text" src="http://image.source"></p></div></div>`)
|
||||
})
|
||||
|
||||
it("allows image elements with https scheme", function() {
|
||||
const str = ``
|
||||
const el = render(<OAS3Markdown source={str} />)
|
||||
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="https://image.source" title="Image title"></p></div></div>`)
|
||||
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img title="Image title" alt="Image alt text" src="https://image.source"></p></div></div>`)
|
||||
})
|
||||
|
||||
it("allows image elements with data scheme", function() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from "react"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { shallow } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import { fromJS, Map } from "immutable"
|
||||
import Models from "components/models"
|
||||
import ModelCollpase from "components/model-collapse"
|
||||
import ModelComponent from "components/model-wrapper"
|
||||
@@ -19,6 +19,7 @@ describe("<Models/>", function(){
|
||||
},
|
||||
specSelectors: {
|
||||
isOAS3: () => false,
|
||||
specJson: () => Map(),
|
||||
definitions: function() {
|
||||
return fromJS({
|
||||
def1: {},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect, { createSpy } from "expect"
|
||||
import expect from "expect"
|
||||
import { render } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import DeepLink from "components/deep-link"
|
||||
@@ -10,7 +10,8 @@ import {Collapse} from "components/layout-utils"
|
||||
const components = {
|
||||
Collapse,
|
||||
DeepLink,
|
||||
OperationContainer: ({ path, method }) => <span className="mocked-op" id={`${path}-${method}`} />
|
||||
OperationContainer: ({ path, method }) => <span className="mocked-op" id={`${path}-${method}`} />,
|
||||
OperationTag: "div",
|
||||
}
|
||||
|
||||
describe("<Operations/>", function(){
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { mount, render } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import SchemesContainer from "containers/schemes"
|
||||
import Schemes from "components/schemes"
|
||||
import { Col } from "components/layout-utils"
|
||||
|
||||
describe("<SchemesContainer/>", function(){
|
||||
|
||||
const components = {
|
||||
schemes: Schemes,
|
||||
Col,
|
||||
authorizeBtn: () => <span className="mocked-button" id="mocked-button" />
|
||||
}
|
||||
const mockedProps = {
|
||||
specSelectors: {
|
||||
securityDefinitions() {},
|
||||
operationScheme() {},
|
||||
schemes() {}
|
||||
},
|
||||
specActions: {
|
||||
setScheme() {}
|
||||
},
|
||||
getComponent: c => components[c]
|
||||
}
|
||||
const twoSecurityDefinitions = {
|
||||
"petstore_auth": {
|
||||
"type": "oauth2",
|
||||
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
|
||||
"flow": "implicit",
|
||||
"scopes": {
|
||||
"write:pets": "modify pets in your account",
|
||||
"read:pets": "read your pets"
|
||||
}
|
||||
},
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
"in": "header"
|
||||
}
|
||||
}
|
||||
|
||||
it("renders Schemes inside SchemesContainer if schemes are provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.operationScheme = function() {return "http"}
|
||||
props.specSelectors.schemes = function() {return fromJS(["http", "https"])}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<SchemesContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedSchemes = wrapper.find(Schemes)
|
||||
expect(renderedSchemes.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("does not render Schemes inside SchemeWrapper if empty array of schemes is provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.schemes = function() {return fromJS([])}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<SchemesContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedSchemes = wrapper.find(Schemes)
|
||||
expect(renderedSchemes.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("does not render Schemes inside SchemeWrapper if provided schemes are undefined", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.schemes = function() {return undefined}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<SchemesContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedSchemes = wrapper.find(Schemes)
|
||||
expect(renderedSchemes.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("renders AuthorizeBtn inside SchemesContainer if security definition is provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.securityDefinitions = function () {return fromJS(twoSecurityDefinitions)}
|
||||
|
||||
// When
|
||||
let wrapper = render(<SchemesContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedAuthorizeBtn = wrapper.find("span.mocked-button")
|
||||
expect(renderedAuthorizeBtn.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("does not render AuthorizeBtn if security definition is not provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
|
||||
// When
|
||||
let wrapper = render(<SchemesContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedAuthorizeBtn = wrapper.find("span.mocked-button")
|
||||
expect(renderedAuthorizeBtn.length).toEqual(0)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,70 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { shallow } from "enzyme"
|
||||
import { fromJS, Map } from "immutable"
|
||||
import VersionPragmaFilter from "components/version-pragma-filter"
|
||||
|
||||
describe("<VersionPragmaFilter/>", function(){
|
||||
it("renders children for a Swagger 2 definition", function(){
|
||||
// When
|
||||
let wrapper = shallow(
|
||||
<VersionPragmaFilter isSwagger2={true} isOAS3={false}>
|
||||
hello!
|
||||
</VersionPragmaFilter>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div").length).toEqual(1)
|
||||
expect(wrapper.find("div").text()).toEqual("hello!")
|
||||
})
|
||||
it("renders children for an OpenAPI 3 definition", function(){
|
||||
// When
|
||||
let wrapper = shallow(
|
||||
<VersionPragmaFilter isSwagger2={false} isOAS3={true}>
|
||||
hello!
|
||||
</VersionPragmaFilter>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div").length).toEqual(1)
|
||||
expect(wrapper.find("div").text()).toEqual("hello!")
|
||||
})
|
||||
it("renders children when a bypass prop is set", function(){
|
||||
// When
|
||||
let wrapper = shallow(
|
||||
<VersionPragmaFilter bypass>
|
||||
hello!
|
||||
</VersionPragmaFilter>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div").length).toEqual(1)
|
||||
expect(wrapper.find("div").text()).toEqual("hello!")
|
||||
})
|
||||
it("renders the correct message for an ambiguous-version definition", function(){
|
||||
// When
|
||||
let wrapper = shallow(
|
||||
<VersionPragmaFilter isSwagger2={true} isOAS3={true}>
|
||||
hello!
|
||||
</VersionPragmaFilter>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div.version-pragma__message--ambiguous").length).toEqual(1)
|
||||
expect(wrapper.find("div.version-pragma__message--missing").length).toEqual(0)
|
||||
})
|
||||
it("renders the correct message for a missing-version definition", function(){
|
||||
// When
|
||||
let wrapper = shallow(
|
||||
<VersionPragmaFilter isSwagger2={false} isOAS3={false}>
|
||||
hello!
|
||||
</VersionPragmaFilter>
|
||||
)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div.version-pragma__message--missing").length).toEqual(1)
|
||||
expect(wrapper.find("div.version-pragma__message--ambiguous").length).toEqual(0)
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,68 @@
|
||||
import { fromJS } from "immutable"
|
||||
import { isOAS3, isSwagger2 } from "corePlugins/oas3/helpers"
|
||||
import expect from "expect"
|
||||
|
||||
const isOAS3Shorthand = (version) => isOAS3(fromJS({
|
||||
openapi: version
|
||||
}))
|
||||
|
||||
const isSwagger2Shorthand = (version) => isSwagger2(fromJS({
|
||||
swagger: version
|
||||
}))
|
||||
|
||||
describe("isOAS3", function () {
|
||||
it("should recognize valid OAS3 version values", function () {
|
||||
expect(isOAS3Shorthand("3.0.0")).toEqual(true)
|
||||
expect(isOAS3Shorthand("3.0.1")).toEqual(true)
|
||||
expect(isOAS3Shorthand("3.0.11111")).toEqual(true)
|
||||
expect(isOAS3Shorthand("3.0.0-rc0")).toEqual(true)
|
||||
})
|
||||
|
||||
it("should fail for invalid OAS3 version values", function () {
|
||||
expect(isOAS3Shorthand("3.0")).toEqual(false)
|
||||
expect(isOAS3Shorthand("3.0.")).toEqual(false)
|
||||
expect(isOAS3Shorthand("2.0")).toEqual(false)
|
||||
})
|
||||
|
||||
it("should gracefully fail for non-string values", function () {
|
||||
expect(isOAS3Shorthand(3.0)).toEqual(false)
|
||||
expect(isOAS3Shorthand(3)).toEqual(false)
|
||||
expect(isOAS3Shorthand({})).toEqual(false)
|
||||
expect(isOAS3Shorthand(null)).toEqual(false)
|
||||
})
|
||||
|
||||
it("should gracefully fail when `openapi` field is missing", function () {
|
||||
expect(isOAS3(fromJS({
|
||||
openApi: "3.0.0"
|
||||
}))).toEqual(false)
|
||||
expect(isOAS3Shorthand(null)).toEqual(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("isSwagger2", function () {
|
||||
it("should recognize valid Swagger 2.0 version values", function () {
|
||||
expect(isSwagger2Shorthand("2.0")).toEqual(true)
|
||||
expect(isSwagger2Shorthand("2.0-rc0")).toEqual(true)
|
||||
})
|
||||
|
||||
it("should fail for invalid Swagger 2.0 version values", function () {
|
||||
expect(isSwagger2Shorthand("3.0")).toEqual(false)
|
||||
expect(isSwagger2Shorthand("3.0.")).toEqual(false)
|
||||
expect(isSwagger2Shorthand("2.1")).toEqual(false)
|
||||
expect(isSwagger2Shorthand("1.2")).toEqual(false)
|
||||
expect(isSwagger2Shorthand("2")).toEqual(false)
|
||||
})
|
||||
|
||||
it("should gracefully fail for non-string values", function () {
|
||||
expect(isSwagger2Shorthand(2.0)).toEqual(false)
|
||||
expect(isSwagger2Shorthand(2)).toEqual(false)
|
||||
expect(isSwagger2Shorthand({})).toEqual(false)
|
||||
expect(isSwagger2Shorthand(null)).toEqual(false)
|
||||
})
|
||||
|
||||
it("should gracefully fail when `swagger` field is missing", function () {
|
||||
expect(isSwagger2(fromJS({
|
||||
Swagger: "2.0"
|
||||
}))).toEqual(false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { mount } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import ServersContainer from "core/plugins/oas3/components/servers-container"
|
||||
import Servers from "core/plugins/oas3/components/servers"
|
||||
import { Col } from "components/layout-utils"
|
||||
|
||||
describe("<ServersContainer/>", function(){
|
||||
|
||||
const components = {
|
||||
Servers,
|
||||
Col
|
||||
}
|
||||
const mockedProps = {
|
||||
specSelectors: {
|
||||
servers() {}
|
||||
},
|
||||
oas3Selectors: {
|
||||
selectedServer() {},
|
||||
serverVariableValue() {},
|
||||
serverEffectiveValue() {}
|
||||
},
|
||||
oas3Actions: {
|
||||
setSelectedServer() {},
|
||||
setServerVariableValue() {}
|
||||
},
|
||||
getComponent: c => components[c]
|
||||
}
|
||||
|
||||
it("renders Servers inside ServersContainer if servers are provided", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.servers = function() {return fromJS([{url: "http://server1.com"}])}
|
||||
props.oas3Selectors = {...mockedProps.oas3Selectors}
|
||||
props.oas3Selectors.selectedServer = function() {return "http://server1.com"}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<ServersContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedServers = wrapper.find(Servers)
|
||||
expect(renderedServers.length).toEqual(1)
|
||||
})
|
||||
|
||||
it("does not render Servers inside ServersContainer if servers are empty", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
props.specSelectors = {...mockedProps.specSelectors}
|
||||
props.specSelectors.servers = function() {return fromJS([])}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<ServersContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedServers = wrapper.find(Servers)
|
||||
expect(renderedServers.length).toEqual(0)
|
||||
})
|
||||
|
||||
it("does not render Servers inside ServersContainer if servers are undefined", function(){
|
||||
|
||||
// Given
|
||||
let props = {...mockedProps}
|
||||
|
||||
// When
|
||||
let wrapper = mount(<ServersContainer {...props}/>)
|
||||
|
||||
// Then
|
||||
const renderedServers = wrapper.find(Servers)
|
||||
expect(renderedServers.length).toEqual(0)
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,35 @@
|
||||
import { fromJS } from "immutable"
|
||||
import { createXMLExample, sampleFromSchema } from "corePlugins/samples/fn"
|
||||
import expect from "expect"
|
||||
|
||||
describe("sampleFromSchema", function() {
|
||||
it("handles Immutable.js objects for nested schemas", function () {
|
||||
var definition = fromJS({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"json": {
|
||||
"type": "object",
|
||||
"example": {
|
||||
"a": "string"
|
||||
},
|
||||
"properties": {
|
||||
"a": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var expected = {
|
||||
json: {
|
||||
a: "string"
|
||||
}
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition, { includeReadOnly: false })).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns object with no readonly fields for parameter", function () {
|
||||
var definition = {
|
||||
type: "object",
|
||||
@@ -351,6 +379,46 @@ describe("sampleFromSchema", function() {
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns null for a null example", function() {
|
||||
var definition = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"example": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var expected = {
|
||||
foo: null
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns null for a null object-level example", function() {
|
||||
var definition = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"foo": null
|
||||
}
|
||||
}
|
||||
|
||||
var expected = {
|
||||
foo: null
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-env mocha */
|
||||
import expect, { createSpy } from "expect"
|
||||
import { fromJS } from "immutable"
|
||||
import { execute, executeRequest } from "corePlugins/spec/actions"
|
||||
import { execute, executeRequest, changeParamByIdentity } from "corePlugins/spec/actions"
|
||||
|
||||
describe("spec plugin - actions", function(){
|
||||
|
||||
@@ -184,4 +184,27 @@ describe("spec plugin - actions", function(){
|
||||
it.skip("should call errActions.newErr, if the fn.execute rejects", function(){
|
||||
})
|
||||
|
||||
describe("changeParamByIdentity", function () {
|
||||
it("should map its arguments to a payload", function () {
|
||||
const pathMethod = ["/one", "get"]
|
||||
const param = fromJS({
|
||||
name: "body",
|
||||
in: "body"
|
||||
})
|
||||
const value = "my value"
|
||||
const isXml = false
|
||||
|
||||
const result = changeParamByIdentity(pathMethod, param, value, isXml)
|
||||
|
||||
expect(result).toEqual({
|
||||
type: "spec_update_param",
|
||||
payload: {
|
||||
path: pathMethod,
|
||||
param,
|
||||
value,
|
||||
isXml
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -129,4 +129,53 @@ describe("spec plugin - reducer", function(){
|
||||
expect(response).toEqual(expectedResult)
|
||||
})
|
||||
})
|
||||
describe("SPEC_UPDATE_PARAM", function() {
|
||||
it("should store parameter values by name+in", () => {
|
||||
const updateParam = reducer["spec_update_param"]
|
||||
|
||||
const path = "/pet/post"
|
||||
const method = "POST"
|
||||
|
||||
const state = fromJS({})
|
||||
const result = updateParam(state, {
|
||||
payload: {
|
||||
path: [path, method],
|
||||
paramName: "body",
|
||||
paramIn: "body",
|
||||
value: `{ "a": 123 }`,
|
||||
isXml: false
|
||||
}
|
||||
})
|
||||
|
||||
const response = result.getIn(["meta", "paths", path, method, "parameters", "body.body", "value"])
|
||||
expect(response).toEqual(`{ "a": 123 }`)
|
||||
})
|
||||
it("should store parameter values by identity", () => {
|
||||
const updateParam = reducer["spec_update_param"]
|
||||
|
||||
const path = "/pet/post"
|
||||
const method = "POST"
|
||||
|
||||
const param = fromJS({
|
||||
name: "body",
|
||||
in: "body",
|
||||
schema: {
|
||||
type: "string"
|
||||
}
|
||||
})
|
||||
|
||||
const state = fromJS({})
|
||||
const result = updateParam(state, {
|
||||
payload: {
|
||||
param,
|
||||
path: [path, method],
|
||||
value: `{ "a": 123 }`,
|
||||
isXml: false
|
||||
}
|
||||
})
|
||||
|
||||
const value = result.getIn(["meta", "paths", path, method, "parameters", `body.body.hash-${param.hashCode()}`, "value"])
|
||||
expect(value).toEqual(`{ "a": 123 }`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,6 +11,11 @@ import {
|
||||
} from "corePlugins/spec/selectors"
|
||||
|
||||
import Petstore from "./assets/petstore.json"
|
||||
import {
|
||||
operationWithMeta,
|
||||
parameterWithMeta,
|
||||
parameterWithMetaByIdentity
|
||||
} from "../../../../src/core/plugins/spec/selectors"
|
||||
|
||||
describe("spec plugin - selectors", function(){
|
||||
|
||||
@@ -451,4 +456,260 @@ describe("spec plugin - selectors", function(){
|
||||
expect(result.getIn(["paths"]).keySeq().toJS()).toEqual(correctOrder)
|
||||
})
|
||||
})
|
||||
|
||||
describe("operationWithMeta", function() {
|
||||
it("should support merging in name+in keyed param metadata", function () {
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [
|
||||
{
|
||||
name: "body",
|
||||
in: "body"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
"body.body": {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = operationWithMeta(state, "/", "get")
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
parameters: [
|
||||
{
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
it("should support merging in hash-keyed param metadata", function () {
|
||||
const bodyParam = fromJS({
|
||||
name: "body",
|
||||
in: "body"
|
||||
})
|
||||
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [
|
||||
bodyParam
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = operationWithMeta(state, "/", "get")
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
parameters: [
|
||||
{
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
})
|
||||
describe("parameterWithMeta", function() {
|
||||
it("should support merging in name+in keyed param metadata", function () {
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [
|
||||
{
|
||||
name: "body",
|
||||
in: "body"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
"body.body": {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = parameterWithMeta(state, ["/", "get"], "body", "body")
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
})
|
||||
})
|
||||
it("should give best-effort when encountering hash-keyed param metadata", function () {
|
||||
const bodyParam = fromJS({
|
||||
name: "body",
|
||||
in: "body"
|
||||
})
|
||||
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [
|
||||
bodyParam
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = parameterWithMeta(state, ["/", "get"], "body", "body")
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
describe("parameterWithMetaByIdentity", function() {
|
||||
it("should support merging in name+in keyed param metadata", function () {
|
||||
const bodyParam = fromJS({
|
||||
name: "body",
|
||||
in: "body"
|
||||
})
|
||||
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [bodyParam]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
"body.body": {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
})
|
||||
})
|
||||
it("should support merging in hash-keyed param metadata", function () {
|
||||
const bodyParam = fromJS({
|
||||
name: "body",
|
||||
in: "body"
|
||||
})
|
||||
|
||||
const state = fromJS({
|
||||
json: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: [
|
||||
bodyParam
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
paths: {
|
||||
"/": {
|
||||
"get": {
|
||||
parameters: {
|
||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
||||
value: "abc123"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
||||
|
||||
expect(result.toJS()).toEqual({
|
||||
name: "body",
|
||||
in: "body",
|
||||
value: "abc123"
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -317,7 +317,7 @@ describe("bound system", function(){
|
||||
|
||||
})
|
||||
|
||||
describe("when selector returns a funtcion", function(){
|
||||
describe("when selector returns a function", function(){
|
||||
|
||||
it("should pass the system to that function", function(){
|
||||
|
||||
|
||||
+94
-3
@@ -350,6 +350,12 @@ describe("utils", function() {
|
||||
expect( result ).toEqual( expectedError )
|
||||
}
|
||||
|
||||
const assertValidateOas3Param = (param, expectedError) => {
|
||||
// for cases where you _only_ want to try OAS3
|
||||
result = validateParam( fromJS(param), false, true )
|
||||
expect( result ).toEqual( expectedError )
|
||||
}
|
||||
|
||||
it("should check the isOAS3 flag when validating parameters", function() {
|
||||
// This should "skip" validation because there is no `schema` property
|
||||
// and we are telling `validateParam` this is an OAS3 spec
|
||||
@@ -361,6 +367,92 @@ describe("utils", function() {
|
||||
expect( result ).toEqual( [] )
|
||||
})
|
||||
|
||||
it("validates required OAS3 objects", function() {
|
||||
// valid object
|
||||
param = {
|
||||
required: true,
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: {
|
||||
abc: 123
|
||||
}
|
||||
}
|
||||
assertValidateOas3Param(param, [])
|
||||
|
||||
// valid object-as-string
|
||||
param = {
|
||||
required: true,
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: JSON.stringify({
|
||||
abc: 123
|
||||
})
|
||||
}
|
||||
assertValidateOas3Param(param, [])
|
||||
|
||||
// invalid object-as-string
|
||||
param = {
|
||||
required: true,
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: "{{}"
|
||||
}
|
||||
assertValidateOas3Param(param, ["Parameter string value must be valid JSON"])
|
||||
|
||||
// missing when required
|
||||
param = {
|
||||
required: true,
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
}
|
||||
assertValidateOas3Param(param, ["Required field is not provided"])
|
||||
})
|
||||
|
||||
it("validates optional OAS3 objects", function() {
|
||||
// valid object
|
||||
param = {
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: {
|
||||
abc: 123
|
||||
}
|
||||
}
|
||||
assertValidateOas3Param(param, [])
|
||||
|
||||
// valid object-as-string
|
||||
param = {
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: JSON.stringify({
|
||||
abc: 123
|
||||
})
|
||||
}
|
||||
assertValidateOas3Param(param, [])
|
||||
|
||||
// invalid object-as-string
|
||||
param = {
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
value: "{{}"
|
||||
}
|
||||
assertValidateOas3Param(param, ["Parameter string value must be valid JSON"])
|
||||
|
||||
// missing when not required
|
||||
param = {
|
||||
schema: {
|
||||
type: "object"
|
||||
},
|
||||
}
|
||||
assertValidateOas3Param(param, [])
|
||||
})
|
||||
|
||||
it("validates required strings", function() {
|
||||
// invalid string
|
||||
param = {
|
||||
@@ -962,7 +1054,7 @@ describe("utils", function() {
|
||||
expect(result).toEqual(Map([[ "minimum", "b"]]))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe("deeplyStripKey", function() {
|
||||
it("should filter out a specified key", function() {
|
||||
const input = {
|
||||
@@ -1065,8 +1157,7 @@ describe("utils", function() {
|
||||
})
|
||||
|
||||
it("should sanitize a `data:` url", function() {
|
||||
const res = sanitizeUrl(`data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGV
|
||||
sbG8iKTs8L3NjcmlwdD4=`)
|
||||
const res = sanitizeUrl(`data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=`)
|
||||
|
||||
expect(res).toEqual("about:blank")
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Swagger UI</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
@@ -75,7 +74,7 @@
|
||||
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
|
||||
// Build a system
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
url: "https://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user