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
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/core/components/version-pragma-filter.jsx
Normal file
54
src/core/components/version-pragma-filter.jsx
Normal file
@@ -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>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -66,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"
|
||||||
@@ -125,6 +126,7 @@ export default function() {
|
|||||||
TryItOutButton,
|
TryItOutButton,
|
||||||
Markdown,
|
Markdown,
|
||||||
BaseLayout,
|
BaseLayout,
|
||||||
|
VersionPragmaFilter,
|
||||||
VersionStamp,
|
VersionStamp,
|
||||||
OperationExt,
|
OperationExt,
|
||||||
OperationExtRow,
|
OperationExtRow,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
70
test/components/version-pragma-filter.js
Normal file
70
test/components/version-pragma-filter.js
Normal 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)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user