Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daea0715d7 | ||
|
|
cdd3663647 | ||
|
|
f1cdb6a032 | ||
|
|
a03c12786a | ||
|
|
a51bf1ea3e | ||
|
|
690e274e07 | ||
|
|
a2fee7ed58 | ||
|
|
90157c1a40 | ||
|
|
5ea2150ae7 | ||
|
|
d91e4e84b8 |
@@ -11,15 +11,6 @@ branches:
|
|||||||
- master
|
- master
|
||||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||||
install: "npm i && npm update"
|
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:
|
before_deploy:
|
||||||
- npm run build
|
- npm run build
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -2,27 +2,25 @@
|
|||||||
|
|
||||||
[](http://badge.fury.io/js/swagger-ui)
|
[](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.
|
**👉🏼 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:
|
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](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 web project that can't resolve npm module dependencies.
|
* [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
|
## 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
|
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.0 | 2018-05-26 | 2.0, 3.0 | [tag v3.17.0](https://github.com/swagger-api/swagger-ui/tree/v3.17.0)
|
||||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||||
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
|
||||||
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
|
||||||
@@ -76,7 +74,7 @@ Please disclose any security-related issues or vulnerabilities by emailing [secu
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright 2017 SmartBear Software
|
Copyright 2018 SmartBear Software
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
Vendored
+45
-72
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -55,7 +55,7 @@ fi
|
|||||||
|
|
||||||
# replace `url` with `urls` option if API_URLS is set
|
# replace `url` with `urls` option if API_URLS is set
|
||||||
if [[ -n "$API_URLS" ]]; then
|
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
|
fi
|
||||||
|
|
||||||
# replace the PORT that nginx listens on if PORT is supplied
|
# replace the PORT that nginx listens on if PORT is supplied
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "swagger-ui",
|
"name": "swagger-ui",
|
||||||
"version": "3.16.0",
|
"version": "3.17.0",
|
||||||
"main": "dist/swagger-ui.js",
|
"main": "dist/swagger-ui.js",
|
||||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export default class BaseLayout extends React.Component {
|
|||||||
let servers = specSelectors.servers()
|
let servers = specSelectors.servers()
|
||||||
|
|
||||||
let SvgAssets = getComponent("SvgAssets")
|
let SvgAssets = getComponent("SvgAssets")
|
||||||
|
let VersionPragmaFilter = getComponent("VersionPragmaFilter")
|
||||||
let Info = getComponent("info")
|
let Info = getComponent("info")
|
||||||
let Operations = getComponent("operations", true)
|
let Operations = getComponent("operations", true)
|
||||||
let Models = getComponent("Models", true)
|
let Models = getComponent("Models", true)
|
||||||
@@ -49,6 +50,9 @@ export default class BaseLayout extends React.Component {
|
|||||||
let Servers = getComponent("Servers")
|
let Servers = getComponent("Servers")
|
||||||
let Errors = getComponent("errors", true)
|
let Errors = getComponent("errors", true)
|
||||||
|
|
||||||
|
let isSwagger2 = specSelectors.isSwagger2()
|
||||||
|
let isOAS3 = specSelectors.isOAS3()
|
||||||
|
|
||||||
let isLoading = specSelectors.loadingStatus() === "loading"
|
let isLoading = specSelectors.loadingStatus() === "loading"
|
||||||
let isFailed = specSelectors.loadingStatus() === "failed"
|
let isFailed = specSelectors.loadingStatus() === "failed"
|
||||||
let filter = layoutSelectors.currentFilter()
|
let filter = layoutSelectors.currentFilter()
|
||||||
@@ -80,7 +84,7 @@ export default class BaseLayout extends React.Component {
|
|||||||
|
|
||||||
<div className='swagger-ui'>
|
<div className='swagger-ui'>
|
||||||
<SvgAssets />
|
<SvgAssets />
|
||||||
<div>
|
<VersionPragmaFilter isSwagger2={isSwagger2} isOAS3={isOAS3} alsoShow={<Errors/>}>
|
||||||
<Errors/>
|
<Errors/>
|
||||||
<Row className="information-container">
|
<Row className="information-container">
|
||||||
<Col mobile={12}>
|
<Col mobile={12}>
|
||||||
@@ -142,7 +146,7 @@ export default class BaseLayout extends React.Component {
|
|||||||
<Models/>
|
<Models/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</VersionPragmaFilter>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
import Im from "immutable"
|
||||||
|
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
|
||||||
|
|
||||||
|
export default class OperationTag extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
tagObj: Im.fromJS({}),
|
||||||
|
tag: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
tagObj: ImPropTypes.map.isRequired,
|
||||||
|
tag: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
layoutSelectors: PropTypes.object.isRequired,
|
||||||
|
layoutActions: PropTypes.object.isRequired,
|
||||||
|
|
||||||
|
getConfigs: PropTypes.func.isRequired,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
children: PropTypes.element,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
tagObj,
|
||||||
|
tag,
|
||||||
|
children,
|
||||||
|
|
||||||
|
layoutSelectors,
|
||||||
|
layoutActions,
|
||||||
|
getConfigs,
|
||||||
|
getComponent,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
let {
|
||||||
|
docExpansion,
|
||||||
|
deepLinking,
|
||||||
|
} = getConfigs()
|
||||||
|
|
||||||
|
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||||
|
|
||||||
|
const Collapse = getComponent("Collapse")
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
|
const DeepLink = getComponent("DeepLink")
|
||||||
|
|
||||||
|
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
||||||
|
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
||||||
|
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
||||||
|
|
||||||
|
let isShownKey = ["operations-tag", createDeepLinkPath(tag)]
|
||||||
|
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} >
|
||||||
|
|
||||||
|
<h4
|
||||||
|
onClick={() => layoutActions.show(isShownKey, !showTag)}
|
||||||
|
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
|
||||||
|
id={isShownKey.join("-")}>
|
||||||
|
<DeepLink
|
||||||
|
enabled={isDeepLinkingEnabled}
|
||||||
|
isShown={showTag}
|
||||||
|
path={tag}
|
||||||
|
text={tag} />
|
||||||
|
{ !tagDescription ? <small></small> :
|
||||||
|
<small>
|
||||||
|
<Markdown source={tagDescription} />
|
||||||
|
</small>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{ !tagExternalDocsDescription ? null :
|
||||||
|
<small>
|
||||||
|
{ tagExternalDocsDescription }
|
||||||
|
{ tagExternalDocsUrl ? ": " : null }
|
||||||
|
{ tagExternalDocsUrl ?
|
||||||
|
<a
|
||||||
|
href={sanitizeUrl(tagExternalDocsUrl)}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
target={"_blank"}
|
||||||
|
>{tagExternalDocsUrl}</a> : null
|
||||||
|
}
|
||||||
|
</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="expand-operation"
|
||||||
|
title={showTag ? "Collapse operation": "Expand operation"}
|
||||||
|
onClick={() => layoutActions.show(isShownKey, !showTag)}>
|
||||||
|
|
||||||
|
<svg className="arrow" width="20" height="20">
|
||||||
|
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<Collapse isOpened={showTag}>
|
||||||
|
{children}
|
||||||
|
</Collapse>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import Im from "immutable"
|
import Im from "immutable"
|
||||||
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
|
|
||||||
|
|
||||||
const SWAGGER2_OPERATION_METHODS = [
|
const SWAGGER2_OPERATION_METHODS = [
|
||||||
"get", "put", "post", "delete", "options", "head", "patch"
|
"get", "put", "post", "delete", "options", "head", "patch"
|
||||||
@@ -38,18 +37,12 @@ export default class Operations extends React.Component {
|
|||||||
let taggedOps = specSelectors.taggedOperations()
|
let taggedOps = specSelectors.taggedOperations()
|
||||||
|
|
||||||
const OperationContainer = getComponent("OperationContainer", true)
|
const OperationContainer = getComponent("OperationContainer", true)
|
||||||
const Collapse = getComponent("Collapse")
|
const OperationTag = getComponent("OperationTag")
|
||||||
const Markdown = getComponent("Markdown")
|
|
||||||
const DeepLink = getComponent("DeepLink")
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
docExpansion,
|
|
||||||
maxDisplayedTags,
|
maxDisplayedTags,
|
||||||
deepLinking
|
|
||||||
} = getConfigs()
|
} = getConfigs()
|
||||||
|
|
||||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
|
||||||
|
|
||||||
let filter = layoutSelectors.currentFilter()
|
let filter = layoutSelectors.currentFilter()
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
@@ -66,88 +59,49 @@ export default class Operations extends React.Component {
|
|||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
taggedOps.map( (tagObj, tag) => {
|
taggedOps.map( (tagObj, tag) => {
|
||||||
let operations = tagObj.get("operations")
|
const 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")
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}>
|
<OperationTag
|
||||||
|
key={"operation-" + tag}
|
||||||
<h4
|
tagObj={tagObj}
|
||||||
onClick={() => layoutActions.show(isShownKey, !showTag)}
|
tag={tag}
|
||||||
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
|
layoutSelectors={layoutSelectors}
|
||||||
id={isShownKey.join("-")}>
|
layoutActions={layoutActions}
|
||||||
<DeepLink
|
getConfigs={getConfigs}
|
||||||
enabled={isDeepLinkingEnabled}
|
getComponent={getComponent}>
|
||||||
isShown={showTag}
|
{
|
||||||
path={tag}
|
operations.map( op => {
|
||||||
text={tag} />
|
const path = op.get("path")
|
||||||
{ !tagDescription ? <small></small> :
|
const method = op.get("method")
|
||||||
<small>
|
const specPath = Im.List(["paths", path, method])
|
||||||
<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])
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: (someday) this logic should probably be in a selector,
|
// FIXME: (someday) this logic should probably be in a selector,
|
||||||
// but doing so would require further opening up
|
// but doing so would require further opening up
|
||||||
// selectors to the plugin system, to allow for dynamic
|
// selectors to the plugin system, to allow for dynamic
|
||||||
// overriding of low-level selectors that other selectors
|
// overriding of low-level selectors that other selectors
|
||||||
// rely on. --KS, 12/17
|
// rely on. --KS, 12/17
|
||||||
const validMethods = specSelectors.isOAS3() ?
|
const validMethods = specSelectors.isOAS3() ?
|
||||||
OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS
|
OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS
|
||||||
|
|
||||||
if(validMethods.indexOf(method) === -1) {
|
if(validMethods.indexOf(method) === -1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <OperationContainer
|
return <OperationContainer
|
||||||
key={`${path}-${method}`}
|
key={`${path}-${method}`}
|
||||||
specPath={specPath}
|
specPath={specPath}
|
||||||
op={op}
|
op={op}
|
||||||
path={path}
|
path={path}
|
||||||
method={method}
|
method={method}
|
||||||
tag={tag}
|
tag={tag}
|
||||||
/>
|
/>
|
||||||
}).toArray()
|
}).toArray()
|
||||||
}
|
}
|
||||||
</Collapse>
|
|
||||||
</div>
|
|
||||||
)
|
</OperationTag>
|
||||||
|
)
|
||||||
}).toArray()
|
}).toArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-7
@@ -27,7 +27,7 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
// Some general settings, that we floated to the top
|
// Some general settings, that we floated to the top
|
||||||
dom_id: null,
|
dom_id: null, // eslint-disable-line camelcase
|
||||||
domNode: null,
|
domNode: null,
|
||||||
spec: {},
|
spec: {},
|
||||||
url: "",
|
url: "",
|
||||||
@@ -131,10 +131,9 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
var system = store.getSystem()
|
var system = store.getSystem()
|
||||||
|
|
||||||
const downloadSpec = (fetchedConfig) => {
|
const downloadSpec = (fetchedConfig) => {
|
||||||
if(typeof constructorConfig !== "object") {
|
if(typeof constructorConfig !== "object") {
|
||||||
return system
|
return system
|
||||||
}
|
}
|
||||||
|
|
||||||
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
||||||
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
||||||
|
|
||||||
@@ -145,6 +144,10 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
|
|
||||||
store.setConfigs(mergedConfig)
|
store.setConfigs(mergedConfig)
|
||||||
|
|
||||||
|
if(system.configsActions) {
|
||||||
|
system.configsActions.loaded()
|
||||||
|
}
|
||||||
|
|
||||||
if (fetchedConfig !== null) {
|
if (fetchedConfig !== null) {
|
||||||
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
||||||
system.specActions.updateUrl("")
|
system.specActions.updateUrl("")
|
||||||
@@ -171,15 +174,17 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
return system
|
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,
|
url: configUrl,
|
||||||
loadRemoteConfig: true,
|
loadRemoteConfig: true,
|
||||||
requestInterceptor: constructorConfig.requestInterceptor,
|
requestInterceptor: constructorConfig.requestInterceptor,
|
||||||
responseInterceptor: constructorConfig.responseInterceptor,
|
responseInterceptor: constructorConfig.responseInterceptor,
|
||||||
}, downloadSpec)) {
|
}, downloadSpec)) {
|
||||||
return downloadSpec()
|
return downloadSpec()
|
||||||
|
} else {
|
||||||
|
system.specActions.getConfigByUrl(configUrl, downloadSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
return system
|
return system
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ export class JsonSchema_boolean extends Component {
|
|||||||
|
|
||||||
onEnumChange = (val) => this.props.onChange(val)
|
onEnumChange = (val) => this.props.onChange(val)
|
||||||
render() {
|
render() {
|
||||||
let { getComponent, value, errors, schema } = this.props
|
let { getComponent, value, errors, schema, required } = this.props
|
||||||
errors = errors.toJS ? errors.toJS() : []
|
errors = errors.toJS ? errors.toJS() : []
|
||||||
|
|
||||||
const Select = getComponent("Select")
|
const Select = getComponent("Select")
|
||||||
@@ -210,7 +210,7 @@ export class JsonSchema_boolean extends Component {
|
|||||||
title={ errors.length ? errors : ""}
|
title={ errors.length ? errors : ""}
|
||||||
value={ String(value) }
|
value={ String(value) }
|
||||||
allowedValues={ fromJS(schema.enum || ["true", "false"]) }
|
allowedValues={ fromJS(schema.enum || ["true", "false"]) }
|
||||||
allowEmptyValue={ !this.props.required }
|
allowEmptyValue={ !schema.enum || !required }
|
||||||
onChange={ this.onEnumChange }/>)
|
onChange={ this.onEnumChange }/>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,3 +18,7 @@ export function toggle(configName) {
|
|||||||
payload: configName,
|
payload: configName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hook
|
||||||
|
export const loaded = () => () => {}
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
// import reducers from "./reducers"
|
import layout from "./layout"
|
||||||
// import * as actions from "./actions"
|
import OperationWrapper from "./operation-wrapper"
|
||||||
// import * as selectors from "./selectors"
|
import OperationTagWrapper from "./operation-tag-wrapper"
|
||||||
import * as specWrapActions from "./spec-wrap-actions"
|
|
||||||
import * as layoutWrapActions from "./layout-wrap-actions"
|
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
return {
|
return [layout, {
|
||||||
statePlugins: {
|
statePlugins: {
|
||||||
spec: {
|
configs: {
|
||||||
wrapActions: specWrapActions
|
wrapActions: {
|
||||||
},
|
loaded: (ori, system) => (...args) => {
|
||||||
layout: {
|
ori(...args)
|
||||||
wrapActions: layoutWrapActions
|
const hash = window.location.hash
|
||||||
|
system.layoutActions.parseDeepLinkHash(hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
wrapComponents: {
|
||||||
|
operation: OperationWrapper,
|
||||||
|
OperationTag: OperationTagWrapper,
|
||||||
|
},
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import { setHash } from "./helpers"
|
|
||||||
import { createDeepLinkPath } from "core/utils"
|
|
||||||
|
|
||||||
export const show = (ori, { getConfigs }) => (...args) => {
|
|
||||||
ori(...args)
|
|
||||||
|
|
||||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
|
||||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
let [thing, shown] = args
|
|
||||||
let [type] = thing
|
|
||||||
|
|
||||||
if(type === "operations-tag" || type === "operations") {
|
|
||||||
if(!shown) {
|
|
||||||
return setHash("/")
|
|
||||||
}
|
|
||||||
|
|
||||||
if(type === "operations") {
|
|
||||||
let [, tag, operationId] = thing
|
|
||||||
setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(type === "operations-tag") {
|
|
||||||
let [, tag] = thing
|
|
||||||
setHash(`/${createDeepLinkPath(tag)}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(e) {
|
|
||||||
// This functionality is not mission critical, so if something goes wrong
|
|
||||||
// we'll just move on
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
import { setHash } from "./helpers"
|
||||||
|
import zenscroll from "zenscroll"
|
||||||
|
import Im, { fromJS } from "immutable"
|
||||||
|
|
||||||
|
const SCROLL_TO = "layout_scroll_to"
|
||||||
|
const CLEAR_SCROLL_TO = "layout_clear_scroll"
|
||||||
|
|
||||||
|
export const show = (ori, { getConfigs, layoutSelectors }) => (...args) => {
|
||||||
|
ori(...args)
|
||||||
|
|
||||||
|
if(!getConfigs().deepLinking) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let [tokenArray, shown] = args
|
||||||
|
//Coerce in to array
|
||||||
|
tokenArray = Array.isArray(tokenArray) ? tokenArray : [tokenArray]
|
||||||
|
// Convert into something we can put in the URL hash
|
||||||
|
// Or return empty, if we cannot
|
||||||
|
const urlHashArray = layoutSelectors.urlHashArrayFromIsShownKey(tokenArray) // Will convert
|
||||||
|
|
||||||
|
// No hash friendly list?
|
||||||
|
if(!urlHashArray.length)
|
||||||
|
return
|
||||||
|
|
||||||
|
const [type, assetName] = urlHashArray
|
||||||
|
|
||||||
|
if (!shown) {
|
||||||
|
return setHash("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlHashArray.length === 2) {
|
||||||
|
setHash(`/${type}/${assetName}`)
|
||||||
|
} else if (urlHashArray.length === 1) {
|
||||||
|
setHash(`/${type}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
// This functionality is not mission critical, so if something goes wrong
|
||||||
|
// we'll just move on
|
||||||
|
console.error(e) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const scrollTo = (path) => {
|
||||||
|
return {
|
||||||
|
type: SCROLL_TO,
|
||||||
|
payload: Array.isArray(path) ? path : [path]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parseDeepLinkHash = (rawHash) => ({ layoutActions, layoutSelectors, getConfigs }) => {
|
||||||
|
|
||||||
|
if(!getConfigs().deepLinking) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rawHash) {
|
||||||
|
let hash = rawHash.slice(1) // # is first character
|
||||||
|
|
||||||
|
|
||||||
|
if(hash[0] === "!") {
|
||||||
|
// Parse UI 2.x shebangs
|
||||||
|
hash = hash.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hash[0] === "/") {
|
||||||
|
// "/pet/addPet" => "pet/addPet"
|
||||||
|
// makes the split result cleaner
|
||||||
|
// also handles forgotten leading slash
|
||||||
|
hash = hash.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isShownKey = layoutSelectors.isShownKeyFromUrlHashArray(hash.split("/"))
|
||||||
|
|
||||||
|
layoutActions.show(isShownKey, true) // TODO: 'show' operation tag
|
||||||
|
layoutActions.scrollTo(isShownKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const readyToScroll = (isShownKey, ref) => (system) => {
|
||||||
|
const scrollToKey = system.layoutSelectors.getScrollToKey()
|
||||||
|
|
||||||
|
if(Im.is(scrollToKey, fromJS(isShownKey))) {
|
||||||
|
system.layoutActions.scrollToElement(ref)
|
||||||
|
system.layoutActions.clearScrollTo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll to "ref" (dom node) with the scrollbar on "container" or the nearest parent
|
||||||
|
export const scrollToElement = (ref, container) => (system) => {
|
||||||
|
try {
|
||||||
|
container = container || system.fn.getScrollParent(ref)
|
||||||
|
let myScroller = zenscroll.createScroller(container)
|
||||||
|
myScroller.to(ref)
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e) // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const clearScrollTo = () => {
|
||||||
|
return {
|
||||||
|
type: CLEAR_SCROLL_TO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From: https://stackoverflow.com/a/42543908/3933724
|
||||||
|
// Modified to return html instead of body element as last resort
|
||||||
|
function getScrollParent(element, includeHidden) {
|
||||||
|
const LAST_RESORT = document.documentElement
|
||||||
|
let style = getComputedStyle(element)
|
||||||
|
const excludeStaticParent = style.position === "absolute"
|
||||||
|
const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/
|
||||||
|
|
||||||
|
if (style.position === "fixed")
|
||||||
|
return LAST_RESORT
|
||||||
|
for (let parent = element; (parent = parent.parentElement);) {
|
||||||
|
style = getComputedStyle(parent)
|
||||||
|
if (excludeStaticParent && style.position === "static") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX))
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
|
||||||
|
return LAST_RESORT
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
fn: {
|
||||||
|
getScrollParent,
|
||||||
|
},
|
||||||
|
statePlugins: {
|
||||||
|
layout: {
|
||||||
|
actions: {
|
||||||
|
scrollToElement,
|
||||||
|
scrollTo,
|
||||||
|
clearScrollTo,
|
||||||
|
readyToScroll,
|
||||||
|
parseDeepLinkHash
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
getScrollToKey(state) {
|
||||||
|
return state.get("scrollToKey")
|
||||||
|
},
|
||||||
|
isShownKeyFromUrlHashArray(state, urlHashArray) {
|
||||||
|
const [tag, operationId] = urlHashArray
|
||||||
|
// We only put operations in the URL
|
||||||
|
if(operationId) {
|
||||||
|
return ["operations", tag, operationId]
|
||||||
|
} else if (tag) {
|
||||||
|
return ["operations-tag", tag]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
urlHashArrayFromIsShownKey(state, isShownKey) {
|
||||||
|
let [type, tag, operationId] = isShownKey
|
||||||
|
// We only put operations in the URL
|
||||||
|
if(type == "operations") {
|
||||||
|
return [tag, operationId]
|
||||||
|
} else if (type == "operations-tag") {
|
||||||
|
return [tag]
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
[SCROLL_TO](state, action) {
|
||||||
|
return state.set("scrollToKey", Im.fromJS(action.payload))
|
||||||
|
},
|
||||||
|
[CLEAR_SCROLL_TO](state) {
|
||||||
|
return state.delete("scrollToKey")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wrapActions: {
|
||||||
|
show
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { PropTypes } from "prop-types"
|
||||||
|
|
||||||
|
const Wrapper = (Ori, system) => class OperationTagWrapper extends React.Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
tag: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad = (ref) => {
|
||||||
|
const { tag } = this.props
|
||||||
|
const isShownKey = ["operations-tag", tag]
|
||||||
|
system.layoutActions.readyToScroll(isShownKey, ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span ref={this.onLoad}>
|
||||||
|
<Ori {...this.props} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wrapper
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import React from "react"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
|
||||||
|
const Wrapper = (Ori, system) => class OperationWrapper extends React.Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
operation: ImPropTypes.map.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad = (ref) => {
|
||||||
|
const { operation } = this.props
|
||||||
|
const { tag, operationId } = operation.toObject()
|
||||||
|
const isShownKey = ["operations", tag, operationId]
|
||||||
|
system.layoutActions.readyToScroll(isShownKey, ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span ref={this.onLoad}>
|
||||||
|
<Ori {...this.props} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wrapper
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import zenscroll from "zenscroll"
|
|
||||||
import { escapeDeepLinkPath } from "core/utils"
|
|
||||||
|
|
||||||
let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed
|
|
||||||
|
|
||||||
|
|
||||||
export const updateJsonSpec = (ori, { layoutActions, getConfigs }) => (...args) => {
|
|
||||||
ori(...args)
|
|
||||||
|
|
||||||
const isDeepLinkingEnabled = getConfigs().deepLinking
|
|
||||||
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if(window.location.hash && !hasHashBeenParsed ) {
|
|
||||||
let hash = window.location.hash.slice(1) // # is first character
|
|
||||||
|
|
||||||
if(hash[0] === "!") {
|
|
||||||
// Parse UI 2.x shebangs
|
|
||||||
hash = hash.slice(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hash[0] === "/") {
|
|
||||||
// "/pet/addPet" => "pet/addPet"
|
|
||||||
// makes the split result cleaner
|
|
||||||
// also handles forgotten leading slash
|
|
||||||
hash = hash.slice(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
let [tag, operationId] = hash.split("/")
|
|
||||||
|
|
||||||
let swaggerUI = document.querySelector(".swagger-ui")
|
|
||||||
let myScroller = zenscroll.createScroller(swaggerUI)
|
|
||||||
|
|
||||||
let target
|
|
||||||
|
|
||||||
if(tag && operationId) {
|
|
||||||
// Pre-expand and scroll to the operation
|
|
||||||
layoutActions.show(["operations-tag", tag], true)
|
|
||||||
layoutActions.show(["operations", tag, operationId], true)
|
|
||||||
|
|
||||||
target = document
|
|
||||||
.getElementById(`operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`)
|
|
||||||
} else if(tag) {
|
|
||||||
// Pre-expand and scroll to the tag
|
|
||||||
layoutActions.show(["operations-tag", tag], true)
|
|
||||||
|
|
||||||
target = document.getElementById(`operations-tag-${escapeDeepLinkPath(tag)}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(target) {
|
|
||||||
myScroller.to(target)
|
|
||||||
setTimeout(() => {
|
|
||||||
// Backup functionality: if we're still at the top of the document,
|
|
||||||
// scroll on the entire page (not within the Swagger-UI container)
|
|
||||||
if(zenscroll.getY() === 0) {
|
|
||||||
zenscroll.to(target)
|
|
||||||
}
|
|
||||||
}, 50)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hasHashBeenParsed = true
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ export function isOAS3(jsSpec) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return oasVersion.startsWith("3")
|
return oasVersion.startsWith("3.0.")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSwagger2(jsSpec) {
|
export function isSwagger2(jsSpec) {
|
||||||
@@ -15,7 +15,7 @@ export function isSwagger2(jsSpec) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return swaggerVersion.startsWith("2")
|
return swaggerVersion.startsWith("2.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OAS3ComponentWrapFactory(Component) {
|
export function OAS3ComponentWrapFactory(Component) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const updateJsonSpec = (ori, {specActions}) => (...args) => {
|
|||||||
|
|
||||||
// Trigger resolution of any path-level $refs.
|
// Trigger resolution of any path-level $refs.
|
||||||
const [json] = args
|
const [json] = args
|
||||||
const pathItems = get(json, ["paths"])
|
const pathItems = get(json, ["paths"]) || {}
|
||||||
const pathItemKeys = Object.keys(pathItems)
|
const pathItemKeys = Object.keys(pathItems)
|
||||||
|
|
||||||
pathItemKeys.forEach(k => {
|
pathItemKeys.forEach(k => {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import Clear from "core/components/clear"
|
|||||||
import LiveResponse from "core/components/live-response"
|
import LiveResponse from "core/components/live-response"
|
||||||
import OnlineValidatorBadge from "core/components/online-validator-badge"
|
import OnlineValidatorBadge from "core/components/online-validator-badge"
|
||||||
import Operations from "core/components/operations"
|
import Operations from "core/components/operations"
|
||||||
|
import OperationTag from "core/components/operation-tag"
|
||||||
import Operation from "core/components/operation"
|
import Operation from "core/components/operation"
|
||||||
import OperationExt from "core/components/operation-extensions"
|
import OperationExt from "core/components/operation-extensions"
|
||||||
import OperationExtRow from "core/components/operation-extension-row"
|
import OperationExtRow from "core/components/operation-extension-row"
|
||||||
@@ -65,6 +66,7 @@ import ArrayModel from "core/components/array-model"
|
|||||||
import PrimitiveModel from "core/components/primitive-model"
|
import PrimitiveModel from "core/components/primitive-model"
|
||||||
import Property from "core/components/property"
|
import Property from "core/components/property"
|
||||||
import TryItOutButton from "core/components/try-it-out-button"
|
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 VersionStamp from "core/components/version-stamp"
|
||||||
import DeepLink from "core/components/deep-link"
|
import DeepLink from "core/components/deep-link"
|
||||||
import SvgAssets from "core/components/svg-assets"
|
import SvgAssets from "core/components/svg-assets"
|
||||||
@@ -124,10 +126,12 @@ export default function() {
|
|||||||
TryItOutButton,
|
TryItOutButton,
|
||||||
Markdown,
|
Markdown,
|
||||||
BaseLayout,
|
BaseLayout,
|
||||||
|
VersionPragmaFilter,
|
||||||
VersionStamp,
|
VersionStamp,
|
||||||
OperationExt,
|
OperationExt,
|
||||||
OperationExtRow,
|
OperationExtRow,
|
||||||
ParameterExt,
|
ParameterExt,
|
||||||
|
OperationTag,
|
||||||
OperationContainer,
|
OperationContainer,
|
||||||
DeepLink,
|
DeepLink,
|
||||||
InfoUrl,
|
InfoUrl,
|
||||||
|
|||||||
@@ -796,3 +796,30 @@ a.nostyle {
|
|||||||
cursor: pointer;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -86,6 +86,54 @@ describe("<JsonSchemaForm/>", function(){
|
|||||||
expect(wrapper.find("select option").eq(2).text()).toEqual("false")
|
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(){
|
it("should render the correct options for a required enum boolean parameter", function(){
|
||||||
|
|
||||||
let props = {
|
let props = {
|
||||||
@@ -105,7 +153,8 @@ describe("<JsonSchemaForm/>", function(){
|
|||||||
|
|
||||||
expect(wrapper.find("select").length).toEqual(1)
|
expect(wrapper.find("select").length).toEqual(1)
|
||||||
expect(wrapper.find("select option").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() {
|
describe("objects", function() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import expect, { createSpy } from "expect"
|
import expect from "expect"
|
||||||
import { render } from "enzyme"
|
import { render } from "enzyme"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import DeepLink from "components/deep-link"
|
import DeepLink from "components/deep-link"
|
||||||
@@ -10,7 +10,8 @@ import {Collapse} from "components/layout-utils"
|
|||||||
const components = {
|
const components = {
|
||||||
Collapse,
|
Collapse,
|
||||||
DeepLink,
|
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(){
|
describe("<Operations/>", function(){
|
||||||
|
|||||||
@@ -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)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user