Compare commits

...
35 Commits
Author SHA1 Message Date
kyle 22ff456c7d housekeeping: remove Q&A section from feature template 2018-07-09 17:01:48 -05:00
kyle 9709df82d3 v3.17.3 (#4706)
* fix: handle formencoded array data correctly

* v3.17.3

* rebuild dist
2018-07-07 02:56:54 -05:00
kyle 4055f51b93 fix: support multimedia media types for file upload (#4705) 2018-07-07 02:36:48 -05:00
kyle 8f65483510 fix: handle urlencoded array data correctly + don't stringify non-object sample values (#4704)
* fix: handle urlencoded array data correctly

* fix: don't stringify non-object sample values

* fix linter
2018-07-07 02:30:40 -05:00
Markus Poerschke 875caab173 improvement: prevent loading resources from third party CDN (via #4598)
Remove usage of Google Fonts to avoid any data protection issue. Using a
CDN will leak data to a third party that can be simply avoided by using
system fonts instead.

Furthermore the usage of CDNs can cause legal issues in EU countries.
2018-07-05 21:55:25 -05:00
kyle ef95d6e00c housekeeping: use bundlesize (#4701)
* housekeeping: use bundlesize

* evaluate bundle size after success
2018-07-05 14:33:16 -05:00
kyle 21b0037529 improvement: handle more invalid Swagger/OpenAPI version values gracefully (#4699)
* improvement: handle more invalid version values gracefully

* use source maps in Mocha tests

yields accurate stack trace line numbers
2018-07-05 12:23:36 -05:00
yshkk 3f06bb50fb fix: exchange function name of component Try-it-out (#4687) 2018-07-04 12:53:21 -05:00
kyle f7001f8011 housekeeping: add extraneous module linting (#4697)
preventative measure!
2018-07-04 12:36:49 -05:00
kyle 742f4bcfb3 housekeeping: migrate back to reselect@2 (#4696)
for now!

reselect@3 has [a breaking change](https://github.com/reduxjs/reselect/releases/tag/v3.0.0) that impacts some of our use cases.
2018-07-04 12:16:21 -05:00
kyle bf21ebbc0c v3.17.2 (via #4684)
* improvement: re-enable and improve Models jump-to-path
* preserve function names
without this, a recent Swagger Client change breaks
cc: https://github.com/swagger-api/swagger-js/commit/f8fccb45107c76c0dd45d9d0e4583087b97ef6b3

* bump swagger-client to 3.8.7
* bump selenium-server-standalone-jar
* lock down `selenium-server-standalone-jar` version
* v3.17.2
* parallelize build command
* use npm-run-all for compound scripts
* rebuild dist
2018-06-30 14:26:41 -05:00
kyle 9d02a7d8ad fix(sample-gen): respect null values in examples (via #4679)
* improvement: re-enable and improve Models jump-to-path

* fix(sample-gen): respect null values in examples
2018-06-27 19:40:00 -07:00
kyle a86fcf312a improvement: re-enable and improve Models jump-to-path (#4674) 2018-06-22 21:28:19 -07:00
kyle 815dbe0b5d housekeeping: remove extraneous getbase aliases (#4671)
* remove extraneous Babel alias

* remove extraneous Webpack alias
2018-06-21 23:01:18 -07:00
Dennis Roche b78ec5bd9d Bug/update dependencies (#4543)
* Add package-lock

* Remove karma* as no longer used. mocha is the test runner now

* Update patch and minor dev dependencies

* Update other dev dependencies, one at time

* Update webpack to v3 and fix package warnings

* Update production dependencies

* Update to react-inspector and Remove react-addons-shallow-compare as no longer used/required in 15.6

* Unused dependencies

* brace
* getbase
* matcher
* promise-worker
* react-addons-test-utils
* react-height
* redux-logger
* scroll-to-element
* shallowequal
* whatwg-fetch

* initial perf, which gets stripped out in production (#4131)

* Refactor deep-linking, in the process extracted out OperationsTag (#4349)

* add configsActions.loaded hook

* add OperationTag to hold Operations

* fix test for operations

* refactor deep-linking plugin

* [FIX] nested `url` option replacement when $API_URLS contains `url: .*,` pattern (#4601)

* fix(try-it-out): initially unset required booleans (#4613)

* fix(tio-params): disable empty values for required+enum booleans (#4615)

* feat(rendering): gate rendering based on valid version identifiers (#4614)

* create VersionPragmaFilter component

* use VersionPragmaFilter in BaseLayout

* tighten version idenitifier constraints

* handle case where user specifies a valid `swagger` and `openapi` field

* add traceable class names for each message

* add tests

* linter fixes!

* UNRELATED CHANGE: remove travis short-circuit

* add bypass switch to VersionPragmaFilter

* v3.17.0 (#4616)

* v3.17.0

* rebuild dist

* Update system.js (#4626)

Fix typo

* Revert "initial perf, which gets stripped out in production (#4131)" (#4636)

This reverts commit 5ea2150ae7.

* Update add-plugin.md (#4620)

Fixed some spacing

* fix: sample generation for nested oject schemas (#4648)

* Fix improper markdown (#4645)

escape `|`

* housekeeping: factor out components for easier BaseLayout reuse (#4604)

* improve: wrap schemes to encapsulate rendering logic
* improve: wrap filter to encapsulate rendering logic
* improve: wrap info section to encapsulate rendering logic
* improve: wrap servers plugin to encapsulate rendering logic
* improve: added tests for schemes-wrapper rendering logic
* improve: added tests for info-wrapper rendering logic, also do not render info if info is undefined
* improve: added tests for filter rendering logic
* improve: added tests for servers-wrapper rendering logic
* `InfoWrapper` -> `InfoContainer`
* add `containers` alias to Babel configuration
* `SchemesWrapper` -> `SchemesContainer`
* drop `container` from container file names
* `ServersWrapper` -> `ServersContainer`
* `Filter` -> `FilterContainer`
* follow `core/containers` pattern in BasePreset

* use HTTPS for Petstore by default (#4652)

* housekeeping: update e2e selectors (#4655)

* v3.17.1 (#4656)

* v3.17.1

* rebuild dist

* Doc updates

* Improvement: Hash-keyed Try-It-Out parameter value storage (#4670)

* allow param update by identity + hashed value storage

* add specActions.changeParamByIdentity

* add identity-based lookup support in spec selectors

* migrate `changeParam` usage to `changeParamByIdentity`

* migrate usage of `parameterWithMeta` to `parameterWithMetaByIdentity`

* update invocations of `changeParamByIdentity` to match fn signature

* use OrderedMap throughout hash-based selectors for consistency

* normalize usage of ParameterRow `onChange`

* migrate bug 4557 tests to reflect new ParameterRow interface

* remove exclusive test blocks

* linter fixes

* copy Parameters changes into OAS3 wrapper

* use rawParam for meta lookups in ParameterRow

* drop unused dependencies from `package.json`

* re-pin selenium dependency version
2018-06-21 22:42:28 -07:00
kyle 8e295c23a4 Improvement: Hash-keyed Try-It-Out parameter value storage (#4670)
* allow param update by identity + hashed value storage

* add specActions.changeParamByIdentity

* add identity-based lookup support in spec selectors

* migrate `changeParam` usage to `changeParamByIdentity`

* migrate usage of `parameterWithMeta` to `parameterWithMetaByIdentity`

* update invocations of `changeParamByIdentity` to match fn signature

* use OrderedMap throughout hash-based selectors for consistency

* normalize usage of ParameterRow `onChange`

* migrate bug 4557 tests to reflect new ParameterRow interface

* remove exclusive test blocks

* linter fixes

* copy Parameters changes into OAS3 wrapper

* use rawParam for meta lookups in ParameterRow
2018-06-21 21:36:38 -07:00
Ron 634615346d Merge pull request #4657 from swagger-api/oauth2-doc-updates
Doc updates
2018-06-16 14:16:50 -06:00
Ron 98d6128375 Doc updates 2018-06-16 14:08:42 -06:00
kyle 24faa4690f v3.17.1 (#4656)
* v3.17.1

* rebuild dist
2018-06-16 00:43:19 -07:00
kyle 7c33ae9c49 housekeeping: update e2e selectors (#4655) 2018-06-15 22:38:13 -07:00
kyle bf77474a11 use HTTPS for Petstore by default (#4652) 2018-06-15 14:36:15 -07:00
Sofiia 8416b043ea housekeeping: factor out components for easier BaseLayout reuse (#4604)
* improve: wrap schemes to encapsulate rendering logic
* improve: wrap filter to encapsulate rendering logic
* improve: wrap info section to encapsulate rendering logic
* improve: wrap servers plugin to encapsulate rendering logic
* improve: added tests for schemes-wrapper rendering logic
* improve: added tests for info-wrapper rendering logic, also do not render info if info is undefined
* improve: added tests for filter rendering logic
* improve: added tests for servers-wrapper rendering logic
* `InfoWrapper` -> `InfoContainer`
* add `containers` alias to Babel configuration
* `SchemesWrapper` -> `SchemesContainer`
* drop `container` from container file names
* `ServersWrapper` -> `ServersContainer`
* `Filter` -> `FilterContainer`
* follow `core/containers` pattern in BasePreset
2018-06-14 19:06:20 -07:00
peng weikang 0eb591b78a Fix improper markdown (#4645)
escape `|`
2018-06-14 17:00:40 -07:00
kyle f53f92351e fix: sample generation for nested oject schemas (#4648) 2018-06-14 16:56:03 -07:00
Kenny John Jacob 3fa3e2d89d Update add-plugin.md (#4620)
Fixed some spacing
2018-06-11 16:53:18 -07:00
kyle a2015ee08b Revert "initial perf, which gets stripped out in production (#4131)" (#4636)
This reverts commit 5ea2150ae7.
2018-06-08 23:18:55 -07:00
Kenny John Jacob 8fd919eede Update system.js (#4626)
Fix typo
2018-06-08 16:08:11 -07:00
kyle f1cdb6a032 v3.17.0 (#4616)
* v3.17.0

* rebuild dist
2018-06-01 21:31:19 -07:00
kyle a03c12786a feat(rendering): gate rendering based on valid version identifiers (#4614)
* create VersionPragmaFilter component

* use VersionPragmaFilter in BaseLayout

* tighten version idenitifier constraints

* handle case where user specifies a valid `swagger` and `openapi` field

* add traceable class names for each message

* add tests

* linter fixes!

* UNRELATED CHANGE: remove travis short-circuit

* add bypass switch to VersionPragmaFilter
2018-06-01 16:04:27 -07:00
kyle a51bf1ea3e fix(tio-params): disable empty values for required+enum booleans (#4615) 2018-06-01 15:46:44 -07:00
kyle 690e274e07 fix(try-it-out): initially unset required booleans (#4613) 2018-06-01 13:30:42 -07:00
masacc a2fee7ed58 [FIX] nested url option replacement when $API_URLS contains url: .*, pattern (#4601) 2018-06-01 13:24:22 -07:00
Josh Ponelat 90157c1a40 Refactor deep-linking, in the process extracted out OperationsTag (#4349)
* add configsActions.loaded hook

* add OperationTag to hold Operations

* fix test for operations

* refactor deep-linking plugin
2018-06-01 13:19:44 -07:00
Josh Ponelat 5ea2150ae7 initial perf, which gets stripped out in production (#4131) 2018-05-30 13:44:19 -07:00
kyle d91e4e84b8 docs: README touchups (#4606)
* docs: README touchups

* Update README.md
2018-05-29 11:53:21 -07:00
84 changed files with 22172 additions and 688 deletions
+4 -4
View File
@@ -18,6 +18,10 @@
"expose": "components",
"src": "src/core/components"
},
{
"expose": "containers",
"src": "src/core/containers"
},
{
"expose": "core",
"src": "src/core"
@@ -37,10 +41,6 @@
{
"expose": "less",
"src": "src/less"
},
{
"expose": "base",
"src": "npm:getbase/src/less/base"
}
]
]
+8 -3
View File
@@ -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]
}
}
@@ -4,14 +4,6 @@ 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:
-1
View File
@@ -5,7 +5,6 @@ node_modules
.nyc_output
npm-debug.log*
.eslintcache
package-lock.json
*.iml
selenium-debug.log
test/e2e/db.json
+4 -9
View File
@@ -11,19 +11,12 @@ branches:
- master
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
install: "npm i && npm update"
before_install:
- | # quickly pass if only documentation is being updated
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
TRAVIS_COMMIT_RANGE="FETCH_HEAD...$TRAVIS_BRANCH"
git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)|(^(docs|examples))/' || {
echo "Only docs were updated, stopping build process."
exit
}
fi
before_deploy:
- npm run build
env:
- DOCKER_IMAGE_NAME=swaggerapi/swagger-ui
script:
- npm test
deploy:
- provider: npm
email: apiteam@swagger.io
@@ -61,3 +54,5 @@ after_success:
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
fi;
fi;
- npm run build-bundle
- bundlesize
+1 -1
View File
@@ -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**"
+9 -11
View File
@@ -2,27 +2,25 @@
[![NPM version](https://badge.fury.io/js/swagger-ui.svg)](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.16.0 | 2018-05-26 | 2.0, 3.0 | [tag v3.16.0](https://github.com/swagger-api/swagger-ui/tree/v3.16.0)
3.17.3 | 2018-06-16 | 2.0, 3.0 | [tag v3.17.3](https://github.com/swagger-api/swagger-ui/tree/v3.17.3)
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.
+1 -2
View File
@@ -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,
+1 -2
View File
@@ -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: [
+45 -72
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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"
})
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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: *
+1 -1
View File
@@ -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 -3
View File
@@ -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
+2 -3
View File
@@ -73,6 +73,7 @@ module.exports = function(rules, options) {
uglifyOptions: {
mangle: specialOptions.mangle,
beautify: !specialOptions.mangle,
keep_fnames: true
},
sourceMap: true,
}),
@@ -141,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,
+20131
View File
File diff suppressed because it is too large Load Diff
+51 -62
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.16.0",
"version": "3.17.3",
"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,20 +24,19 @@
"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 just-test-in-node && npm run lint-errors",
"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 --require test/setup.js --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"
@@ -45,59 +44,45 @@
"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.5.1",
"dompurify": "^1.0.4",
"expect": "1.20.2",
"getbase": "^2.8.2",
"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",
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.8.5",
"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",
@@ -109,52 +94,49 @@
"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.7.0",
"extract-text-webpack-plugin": "^2.1.2",
"file-loader": "0.11.2",
"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",
"imports-loader": "^0.8.0",
"jsdom": "^11.10.0",
"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",
"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",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "0.5.9",
"webpack": "^2.6.1",
"webpack-bundle-size-analyzer": "^2.5.0"
"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"
@@ -165,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"
}
]
}
+10
View File
@@ -0,0 +1,10 @@
{
"rules": {
"import/no-extraneous-dependencies": [
2,
{
"devDependencies": false
}
]
}
}
+1 -1
View File
@@ -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 {
+15 -81
View File
@@ -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>
)
}
+5 -1
View File
@@ -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)}>
@@ -64,11 +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() }
displayName={displayName}
specPath={Im.List([...specPathBase, name])}
specPath={specPath}
getComponent={ getComponent }
specSelectors={ specSelectors }
getConfigs = {getConfigs}
@@ -82,6 +85,7 @@ export default class Models extends Component {
</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)}
+108
View File
@@ -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>
)
}
}
+39 -85
View File
@@ -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()
}
+4 -5
View File
@@ -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({})) || param
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 -8
View File
@@ -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,
@@ -30,7 +31,7 @@ export default class ParameterRow extends Component {
let { isOAS3 } = specSelectors
let example = param.get("example")
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in")) || param
let parameter = specSelectors.parameterWithMetaByIdentity(pathMethod, param) || param
let enumValue
if(isOAS3()) {
@@ -56,9 +57,9 @@ 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 = () => {
@@ -72,7 +73,7 @@ export default class ParameterRow extends Component {
let defaultValue = schema.get("default")
let xExampleValue = param.get("x-example") // Swagger 2 only
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
let parameter = specSelectors.parameterWithMetaByIdentity(pathMethod, param)
let value = parameter ? parameter.get("value") : ""
if( param.get("in") !== "body" ) {
@@ -85,7 +86,7 @@ export default class ParameterRow extends Component {
}
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
@@ -101,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 }
@@ -112,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")
+4 -3
View File
@@ -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}
+2 -2
View File
@@ -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>
}
}
+2 -2
View File
@@ -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])
+44
View File
@@ -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>
)
}
}
+32
View File
@@ -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>
)
}
}
+43
View File
@@ -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
View File
@@ -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
+9 -5
View File
@@ -111,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) {
@@ -135,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("")
}
@@ -174,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 ) {
@@ -201,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")
@@ -210,7 +210,7 @@ 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 }/>)
}
}
@@ -264,3 +264,7 @@ export class JsonSchema_object extends PureComponent {
}
}
function valueOrEmptyList(value) {
return List.isList(value) ? value : List()
}
+4
View File
@@ -18,3 +18,7 @@ export function toggle(configName) {
payload: configName,
}
}
// Hook
export const loaded = () => () => {}
+18 -13
View File
@@ -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)
}
}
+181
View File
@@ -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
@@ -10,6 +10,7 @@ const RequestBody = ({
getComponent,
getConfigs,
specSelectors,
fn,
contentType,
isExecute,
specPath,
@@ -35,7 +36,12 @@ const RequestBody = ({
return null
}
if(contentType === "application/octet-stream") {
if(
contentType === "application/octet-stream"
|| contentType.indexOf("image/") === 0
|| contentType.indexOf("audio/") === 0
|| contentType.indexOf("video/") === 0
) {
const Input = getComponent("Input")
if(!isExecute) {
@@ -85,6 +91,7 @@ const RequestBody = ({
<td className="col parameters-col_description">
{isExecute ?
<JsonSchemaForm
fn={fn}
dispatchInitialValue={!isFile}
schema={prop}
getComponent={getComponent}
@@ -132,6 +139,7 @@ RequestBody.propTypes = {
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>
)
}
}
+8 -4
View File
@@ -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) {
@@ -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}
+1
View File
@@ -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
+7
View File
@@ -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,
+11 -2
View File
@@ -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
)
},
+27 -19
View File
@@ -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
+10
View File
@@ -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,
+5 -3
View File
@@ -37,7 +37,7 @@ export function objectify (thing) {
if(!isObject(thing))
return {}
if(isImmutable(thing))
return thing.toObject()
return thing.toJS()
return thing
}
@@ -628,7 +628,9 @@ export const getSampleSchema = (schema, contentType="", config={}) => {
return memoizedCreateXMLExample(schema, config)
}
return JSON.stringify(memoizedSampleFromSchema(schema, config), null, 2)
const res = memoizedSampleFromSchema(schema, config)
return typeof res === "object" ? JSON.stringify(res, null, 2) : res
}
export const parseSearch = () => {
@@ -742,7 +744,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
}
+1 -1
View File
@@ -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
+27
View File
@@ -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;
}
}
}
+8
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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"
+1
View File
@@ -3,3 +3,4 @@ env:
rules:
"react/prop-types": 1 # bah humbug
"no-unused-vars": 1 # unused vars in tests can be useful for indicating a full signature
"no-global-assign": 1
+10 -4
View File
@@ -18,12 +18,14 @@ describe("bug #4557: default parameter values", function(){
getComponent: ()=> "div",
specSelectors: {
security(){},
parameterWithMeta(){ return paramValue },
parameterWithMetaByIdentity(){ return paramValue },
isOAS3(){ return false }
},
fn: {},
operation: {get: ()=>{}},
onChange: createSpy(),
param: paramValue,
rawParam: paramValue,
onChangeConsumes: () => {},
pathMethod: [],
getConfigs: () => { return {} },
@@ -32,7 +34,8 @@ describe("bug #4557: default parameter values", function(){
render(<ParameterRow {...props}/>)
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue")
expect(props.onChange).toHaveBeenCalled()
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue", false)
})
it("should apply an OpenAPI 3.0 default value", function(){
@@ -48,12 +51,14 @@ describe("bug #4557: default parameter values", function(){
getComponent: ()=> "div",
specSelectors: {
security(){},
parameterWithMeta(){ return paramValue },
parameterWithMetaByIdentity(){ return paramValue },
isOAS3(){ return true }
},
fn: {},
operation: {get: ()=>{}},
onChange: createSpy(),
param: paramValue,
rawParam: paramValue,
onChangeConsumes: () => {},
pathMethod: [],
getConfigs: () => { return {} },
@@ -62,6 +67,7 @@ describe("bug #4557: default parameter values", function(){
render(<ParameterRow {...props}/>)
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue")
expect(props.onChange).toHaveBeenCalled()
expect(props.onChange).toHaveBeenCalledWith(paramValue, "MyDefaultValue", false)
})
})
+65
View File
@@ -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)
})
})
+67
View File
@@ -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)
})
})
+50 -1
View File
@@ -86,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 = {
@@ -105,7 +153,8 @@ 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() {
+3 -2
View File
@@ -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(){
+119
View File
@@ -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)
})
})
+70
View File
@@ -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)
})
})
+68
View File
@@ -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)
})
})
+77
View File
@@ -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)
})
})
+68
View File
@@ -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)
})
})
})
+24 -1
View File
@@ -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
}
})
})
})
})
+49
View File
@@ -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 }`)
})
})
})
+261
View File
@@ -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"
})
})
})
})
+1 -1
View File
@@ -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(){
+27 -1
View File
@@ -24,7 +24,8 @@ import {
getCommonExtensions,
sanitizeUrl,
extractFileNameFromContentDispositionHeader,
deeplyStripKey
deeplyStripKey,
getSampleSchema
} from "core/utils"
import win from "core/window"
@@ -1186,5 +1187,30 @@ describe("utils", function() {
expect(sanitizeUrl({})).toEqual("")
})
})
describe("getSampleSchema", function() {
const oriDate = Date
before(function() {
Date = function () {
this.toISOString = function () {
return "2018-07-07T07:07:05.189Z"
}
}
})
after(function() {
Date = oriDate
})
it("should not unnecessarily stringify non-object values", function() {
// Given
const res = getSampleSchema({
type: "string",
format: "date-time"
})
// Then
expect(res).toEqual(new Date().toISOString())
})
})
})
+1 -2
View File
@@ -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,
+2 -2
View File
@@ -21,7 +21,7 @@
"selenium" : {
"start_process" : true,
"server_path" : "node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-3.4.0.jar",
"server_path" : "node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-3.12.0.jar",
"log_path" : "",
"host" : "127.0.0.1",
"port" : 4444,
@@ -60,4 +60,4 @@
}
}
}
}
}
+124 -124
View File
@@ -85,404 +85,404 @@ module.exports = {
}
},
apiWrapper: {
selector: ".swagger-ui .wrapper:nth-child(3)",
selector: "div.swagger-ui > div:nth-child(2) > div:nth-child(5) > section > div",
elements: {
petAPIWrapper: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1)"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(1) > div"
},
petAPIWrapperBar: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) .opblock-tag"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(1) > div .opblock-tag"
},
/**
* Post pet/ api
*/
petOperationPostContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet"
selector: "div#operations-pet-addPet"
},
petOperationPostTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet .opblock-summary-post span.opblock-summary-path span"
selector: "div#operations-pet-addPet .opblock-summary-post span.opblock-summary-path span"
},
petOperationPostCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet .opblock-summary-post"
selector: "div#operations-pet-addPet .opblock-summary-post"
},
petOperationPostCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet>div:nth-child(2)"
selector: "div#operations-pet-addPet>div:nth-child(2)"
},
petOperationPostTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet button.try-out__btn"
selector: "div#operations-pet-addPet button.try-out__btn"
},
petOperationPostTryText: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet textarea.body-param__text"
selector: "div#operations-pet-addPet textarea.body-param__text"
},
petOperationPostExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet button.execute"
selector: "div#operations-pet-addPet button.execute"
},
petOperationPostTryTextArea: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet textarea"
selector: "div#operations-pet-addPet textarea"
},
petOperationPostResultsBox: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight"
selector: "div#operations-pet-addPet pre.microlight"
},
petOperationPostMockCategoryID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(17)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(17)"
},
petOperationPostMockCategoryName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(23)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(23)"
},
petOperationPostMockName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(31)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(31)"
},
petOperationPostTagID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(54)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(54)"
},
petOperationPostTagName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(60)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(60)"
},
petOperationPostStatus: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(70)"
selector: "div#operations-pet-addPet pre.microlight span:nth-child(70)"
},
/**
* Put pet/ api
*/
petOperationPutContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet"
selector: "div#operations-pet-updatePet"
},
petOperationPutTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet .opblock-summary-put span.opblock-summary-path span"
selector: "div#operations-pet-updatePet .opblock-summary-put span.opblock-summary-path span"
},
petOperationPutCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet .opblock-summary-put"
selector: "div#operations-pet-updatePet .opblock-summary-put"
},
petOperationPutCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet>div:nth-child(2)"
selector: "div#operations-pet-updatePet>div:nth-child(2)"
},
petOperationPutTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet button.try-out__btn"
selector: "div#operations-pet-updatePet button.try-out__btn"
},
petOperationPutTryText: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet textarea.body-param__text"
selector: "div#operations-pet-updatePet textarea.body-param__text"
},
petOperationPutExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet button.execute"
selector: "div#operations-pet-updatePet button.execute"
},
petOperationPutTryTextArea: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet textarea"
selector: "div#operations-pet-updatePet textarea"
},
petOperationPutResultsBox: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight"
selector: "div#operations-pet-updatePet pre.microlight"
},
petOperationPutMockCategoryID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(17)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(17)"
},
petOperationPutMockCategoryName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(23)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(23)"
},
petOperationPutMockName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(31)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(31)"
},
petOperationPutTagID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(54)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(54)"
},
petOperationPutTagName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(60)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(60)"
},
petOperationPutStatus: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(70)"
selector: "div#operations-pet-updatePet pre.microlight span:nth-child(70)"
},
/**
* Get /pet/findByTags
*/
petOperationGetByTagContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags"
selector: "div#operations-pet-findPetsByTags"
},
petOperationGetByTagTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .opblock-summary-get span.opblock-summary-path__deprecated span"
selector: "div#operations-pet-findPetsByTags .opblock-summary-get span.opblock-summary-path__deprecated span"
},
petOperationGetByTagCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .opblock-summary-get"
selector: "div#operations-pet-findPetsByTags .opblock-summary-get"
},
petOperationGetByTagCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .ReactCollapse--collapse"
selector: "div#operations-pet-findPetsByTags .ReactCollapse--collapse"
},
petOperationGetByTagTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.try-out__btn"
selector: "div#operations-pet-findPetsByTags button.try-out__btn"
},
petOperationGetByTagTryAdded: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.json-schema-form-item-add"
selector: "div#operations-pet-findPetsByTags button.json-schema-form-item-add"
},
petOperationGetByTagExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.execute"
selector: "div#operations-pet-findPetsByTags button.execute"
},
petOperationGetByTagTryTextArea: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags textarea"
selector: "div#operations-pet-findPetsByTags textarea"
},
petOperationGetByTagResultsBox: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight"
selector: "div#operations-pet-findPetsByTags pre.microlight"
},
petOperationGetByTagMockCategoryID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(17)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(17)"
},
petOperationGetByTagMockCategoryName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(23)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(23)"
},
petOperationGetByTagMockName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(31)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(31)"
},
petOperationGetByTagTagID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(54)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(54)"
},
petOperationGetByTagTagName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(60)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(60)"
},
petOperationGetByTagStatus: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(70)"
selector: "div#operations-pet-findPetsByTags pre.microlight span:nth-child(70)"
},
/**
* Get /pet/{petId}
*/
petOperationGetByIdContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById"
selector: "div#operations-pet-getPetById"
},
petOperationGetByIdTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById .opblock-summary-get span.opblock-summary-path span"
selector: "div#operations-pet-getPetById .opblock-summary-get span.opblock-summary-path span"
},
petOperationGetByIdCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById .opblock-summary-get"
selector: "div#operations-pet-getPetById .opblock-summary-get"
},
petOperationGetByIdCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById .ReactCollapse--collapse"
selector: "div#operations-pet-getPetById .ReactCollapse--collapse"
},
petOperationGetByIdTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById button.try-out__btn"
selector: "div#operations-pet-getPetById button.try-out__btn"
},
petOperationGetByIdExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById button.execute"
selector: "div#operations-pet-getPetById button.execute"
},
petOperationGetByIdParameter: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-pet-getPetById div.parameters-col_description input"
},
selector: "div#operations-pet-getPetById div.parameters-col_description input"
},
petOperationGetByIdResultsBox: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-getPetById pre.microlight"
},
selector: "div#operations-pet-getPetById pre.microlight"
},
/**
* Delete pet/
*/
petOperationDeleteContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet"
selector: "div#operations-pet-deletePet"
},
petOperationDeleteTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet .opblock-summary-delete span.opblock-summary-path span"
selector: "div#operations-pet-deletePet .opblock-summary-delete span.opblock-summary-path span"
},
petOperationDeleteCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet .opblock-summary-delete"
selector: "div#operations-pet-deletePet .opblock-summary-delete"
},
petOperationDeleteCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet>div:nth-child(2)"
selector: "div#operations-pet-deletePet>div:nth-child(2)"
},
petOperationDeleteTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet button.try-out__btn"
selector: "div#operations-pet-deletePet button.try-out__btn"
},
petOperationDeleteExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet button.execute"
selector: "div#operations-pet-deletePet button.execute"
},
petOperationDeleteTryTextArea: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet textarea"
selector: "div#operations-pet-deletePet textarea"
},
petOperationDeleteResultsBox: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight"
selector: "div#operations-pet-deletePet pre.microlight"
},
petOperationDeleteMockCategoryID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(17)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(17)"
},
petOperationDeleteMockCategoryName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(23)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(23)"
},
petOperationDeleteMockName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(31)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(31)"
},
petOperationDeleteTagID: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(54)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(54)"
},
petOperationDeleteTagName: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(60)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(60)"
},
petOperationDeleteStatus: {
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(70)"
selector: "div#operations-pet-deletePet pre.microlight span:nth-child(70)"
},
/**
* ***********Store************
*/
storeAPIWrapper: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2)"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(2) > div"
},
storeAPIWrapperBar: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) .opblock-tag"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(2) > div .opblock-tag"
},
/**
* Get /store/inventory
*/
storeOperationGetContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory"
selector: "div#operations-store-getInventory"
},
storeOperationGetTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory .opblock-summary-get span.opblock-summary-path span"
selector: "div#operations-store-getInventory .opblock-summary-get span.opblock-summary-path span"
},
storeOperationGetCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory .opblock-summary-get"
selector: "div#operations-store-getInventory .opblock-summary-get"
},
storeOperationGetCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory>div:nth-child(2)"
selector: "div#operations-store-getInventory>div:nth-child(2)"
},
storeOperationGetTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory button.try-out__btn"
selector: "div#operations-store-getInventory button.try-out__btn"
},
storeOperationGetExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory button.execute"
selector: "div#operations-store-getInventory button.execute"
},
storeOperationResponseProps1: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(6)"
selector: "div#operations-store-getInventory pre.example.microlight span:nth-child(6)"
},
storeOperationResponseProps2: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(12)"
selector: "div#operations-store-getInventory pre.example.microlight span:nth-child(12)"
},
storeOperationResponseProps3: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(18)"
selector: "div#operations-store-getInventory pre.example.microlight span:nth-child(18)"
},
/**
* Post /store/order
*/
storeOperationPostContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder"
selector: "div#operations-store-placeOrder"
},
storeOperationPostTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder .opblock-summary-post span.opblock-summary-path span"
selector: "div#operations-store-placeOrder .opblock-summary-post span.opblock-summary-path span"
},
storeOperationPostCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder .opblock-summary-post"
selector: "div#operations-store-placeOrder .opblock-summary-post"
},
storeOperationPostCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder>div:nth-child(2)"
selector: "div#operations-store-placeOrder>div:nth-child(2)"
},
storeOperationPostTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder button.try-out__btn"
selector: "div#operations-store-placeOrder button.try-out__btn"
},
storeOperationPostExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder button.execute"
selector: "div#operations-store-placeOrder button.execute"
},
storeOperationPostResponseId: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(22)"
selector: "div#operations-store-placeOrder pre.example.microlight span:nth-child(22)"
},
storeOperationPostResponsePetId: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(31)"
selector: "div#operations-store-placeOrder pre.example.microlight span:nth-child(31)"
},
storeOperationPostResponseQuantity: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(40)"
selector: "div#operations-store-placeOrder pre.example.microlight span:nth-child(40)"
},
storeOperationPostResponseStatus: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(66)"
selector: "div#operations-store-placeOrder pre.example.microlight span:nth-child(66)"
},
storeOperationPostResponseComplete: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(75)"
selector: "div#operations-store-placeOrder pre.example.microlight span:nth-child(75)"
},
/**
* Delete /store/order/{orderId}
*/
storeOperationDeleteContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder"
selector: "div#operations-store-deleteOrder"
},
storeOperationDeleteTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder .opblock-summary-delete span.opblock-summary-path span"
selector: "div#operations-store-deleteOrder .opblock-summary-delete span.opblock-summary-path span"
},
storeOperationDeleteCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder .opblock-summary-delete"
selector: "div#operations-store-deleteOrder .opblock-summary-delete"
},
storeOperationDeleteCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder>div:nth-child(2)"
selector: "div#operations-store-deleteOrder>div:nth-child(2)"
},
storeOperationDeleteTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder button.try-out__btn"
selector: "div#operations-store-deleteOrder button.try-out__btn"
},
storeOperationDeleteExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder button.execute"
selector: "div#operations-store-deleteOrder button.execute"
},
storeOperationGetResponseHeaders: {
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder pre span"
selector: "div#operations-store-deleteOrder pre span"
},
/**
* *********User**************
*/
userAPIWrapper: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3)"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(3) > div"
},
userAPIWrapperBar: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) .opblock-tag"
selector: "div.swagger-ui div:nth-child(5) > section > div > span:nth-child(3) > div .opblock-tag"
},
/**
* Put /user/login
*/
userOperationPutContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser"
selector: "div#operations-user-updateUser"
},
userOperationPutTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser .opblock-summary-put span.opblock-summary-path span"
selector: "div#operations-user-updateUser .opblock-summary-put span.opblock-summary-path span"
},
userOperationPutCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser .opblock-summary-put"
selector: "div#operations-user-updateUser .opblock-summary-put"
},
userOperationPutCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser>div:nth-child(2)"
selector: "div#operations-user-updateUser>div:nth-child(2)"
},
userOperationPutTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser button.try-out__btn"
selector: "div#operations-user-updateUser button.try-out__btn"
},
userOperationPutExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser button.execute"
selector: "div#operations-user-updateUser button.execute"
},
userOperationPutParameter: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser div.parameters-col_description input"
selector: "div#operations-user-updateUser div.parameters-col_description input"
},
userOperationPutResponseHeader: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser div.parameters-col_description input"
selector: "div#operations-user-updateUser div.parameters-col_description input"
},
/**
* Delete /user
*/
userOperationDeleteContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser"
selector: "div#operations-user-deleteUser"
},
userOperationDeleteTitle: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser .opblock-summary-delete span.opblock-summary-path span"
selector: "div#operations-user-deleteUser .opblock-summary-delete span.opblock-summary-path span"
},
userOperationDeleteCollpase: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser .opblock-summary-delete"
selector: "div#operations-user-deleteUser .opblock-summary-delete"
},
userOperationDeleteCollapseContainer: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser>div:nth-child(2)"
selector: "div#operations-user-deleteUser>div:nth-child(2)"
},
userOperationDeleteTryBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser button.try-out__btn"
selector: "div#operations-user-deleteUser button.try-out__btn"
},
userOperationDeleteExecuteBtn: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser button.execute"
selector: "div#operations-user-deleteUser button.execute"
},
userOperationDeleteParameter: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser div.parameters-col_description input"
selector: "div#operations-user-deleteUser div.parameters-col_description input"
},
userOperationDeleteResponseHeader: {
selector: ".swagger-ui .opblock-tag-section:nth-child(3) .opblock-delete div.parameters-col_description input"
selector: "div#operations-user-deleteUser div.parameters-col_description input"
},
}
},
/* Model Container */
modelWrapper: {
selector: ".swagger-ui .wrapper:nth-child(4)",
selector: "div.swagger-ui > div:nth-child(2) > div:nth-child(6)",
elements: {
modelContainer: {
selector: ".swagger-ui .models"