Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa24b6aec8 | ||
|
|
2f59c4a5f4 | ||
|
|
d32fe02713 | ||
|
|
446bda369c | ||
|
|
8354132915 | ||
|
|
ca28c8c8d6 | ||
|
|
de231c0325 | ||
|
|
1d00c952d6 | ||
|
|
4e6dc3beec | ||
|
|
4ff629eddd | ||
|
|
dd02778b55 | ||
|
|
e15b4c85c0 | ||
|
|
7e6f74080f | ||
|
|
c6a664302a | ||
|
|
ac634c61ce | ||
|
|
37399958a2 | ||
|
|
44882700c2 | ||
|
|
cecc3b3573 | ||
|
|
263f6feb2f | ||
|
|
356dc81b18 | ||
|
|
a7acd9e004 | ||
|
|
ef9fe9d755 | ||
|
|
ca98ed114a | ||
|
|
c5534a506e | ||
|
|
e0fb125a48 | ||
|
|
012313e236 | ||
|
|
27da2a7d3b | ||
|
|
67dbad445d | ||
|
|
a408fb1f23 | ||
|
|
3a7a8c9c67 | ||
|
|
239d105974 | ||
|
|
4f1a8abd0d | ||
|
|
13fd88f1d2 | ||
|
|
590819ad9b | ||
|
|
ca1a0fa544 | ||
|
|
31e7ce0c5e | ||
|
|
d1258c6b8c | ||
|
|
515726b386 | ||
|
|
7d40d72281 | ||
|
|
a5c7083726 | ||
|
|
14f47654ee | ||
|
|
6488cbb649 | ||
|
|
82b9341a06 | ||
|
|
b9be09709a | ||
|
|
63ee0a874c | ||
|
|
7a4ef07c73 | ||
|
|
d7ae284a0c | ||
|
|
a6944a279c | ||
|
|
b2f7953319 | ||
|
|
39450f7364 | ||
|
|
04fb27b46d | ||
|
|
fd44416238 | ||
|
|
d7424ff248 | ||
|
|
175bc486c7 | ||
|
|
cd6b86e710 |
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
|
||||
|
||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||
------------------ | ------------ | -------------------------- | -----
|
||||
3.2.2 | 2017-09-22 | 2.0, 3.0 | [tag v3.2.2](https://github.com/swagger-api/swagger-ui/tree/v3.2.2)
|
||||
3.3.1 | 2017-10-02 | 2.0, 3.0 | [tag v3.3.1](https://github.com/swagger-api/swagger-ui/tree/v3.3.1)
|
||||
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)
|
||||
@@ -119,7 +119,7 @@ scopeSeparator | scope separator for passing scopes, encoded before calling, def
|
||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`
|
||||
|
||||
```
|
||||
```javascript
|
||||
const ui = SwaggerUIBundle({...})
|
||||
|
||||
// Method can be called in any place after calling constructor SwaggerUIBundle
|
||||
@@ -151,6 +151,8 @@ domNode | The HTML DOM element inside which SwaggerUi will put the user interfac
|
||||
oauth2RedirectUrl | OAuth redirect URL
|
||||
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
||||
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be set to 'model' or 'example', and the default is 'example'.
|
||||
defaultModelExpandDepth | The default expansion depth for models. The default value is 1.
|
||||
configUrl | Configs URL
|
||||
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||
@@ -169,7 +171,7 @@ showMutatedRequest | If set to `true` (the default), uses the mutated request re
|
||||
#### Topbar plugin
|
||||
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
|
||||
|
||||
```
|
||||
```javascript
|
||||
let preset = [
|
||||
// TopbarPlugin,
|
||||
ConfigsPlugin,
|
||||
|
||||
Vendored
+13
-12
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AA4kMA;;;;;;AA65DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAq9TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAo/pBA;;;;;AAk6QA;;;;;AAynBA;AAi0CA;;;;;;AAq/YA;;;;;;AAojaA;AA8lvBA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAonMA;;;;;;AAm5DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAukUA;;;;;;;;;;;;;;AAq4JA;AA4+iBA;;;;;;;;;AA8oIA;;;;;AA87QA;;;;;AAynBA;AAo0CA;;;;;;AA6gZA;;;;;;AAkzZA;AAixYA","sourceRoot":""}
|
||||
Vendored
+3
-3
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA80CA;;;;;;AAqpFA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA6mCA;;;;;;AA41FA","sourceRoot":""}
|
||||
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
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAkzeA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AA67eA","sourceRoot":""}
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.2.2",
|
||||
"version": "3.3.1",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -42,6 +42,7 @@
|
||||
"base64-js": "^1.2.0",
|
||||
"brace": "0.7.0",
|
||||
"classnames": "^2.2.5",
|
||||
"commonmark": "^0.28.1",
|
||||
"css.escape": "1.5.1",
|
||||
"deep-extend": "0.4.1",
|
||||
"expect": "1.20.2",
|
||||
@@ -67,17 +68,17 @@
|
||||
"react-motion": "0.4.4",
|
||||
"react-object-inspector": "0.2.1",
|
||||
"react-redux": "^4.x.x",
|
||||
"react-remarkable": "1.1.1",
|
||||
"react-split-pane": "0.1.57",
|
||||
"redux": "^3.x.x",
|
||||
"redux-immutable": "3.0.8",
|
||||
"redux-logger": "*",
|
||||
"remarkable": "^1.7.1",
|
||||
"reselect": "2.5.3",
|
||||
"sanitize-html": "^1.14.1",
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.1.2",
|
||||
"swagger-client": "^3.2.0",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
|
||||
@@ -16,10 +16,12 @@ export default class ArrayModel extends Component {
|
||||
|
||||
render(){
|
||||
let { getComponent, schema, depth, expandDepth, name } = this.props
|
||||
let description = schema.get("description")
|
||||
let items = schema.get("items")
|
||||
let title = schema.get("title") || name
|
||||
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
|
||||
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref"].indexOf(key) === -1 )
|
||||
|
||||
const Markdown = getComponent("Markdown")
|
||||
const ModelCollapse = getComponent("ModelCollapse")
|
||||
const Model = getComponent("Model")
|
||||
|
||||
@@ -36,15 +38,17 @@ export default class ArrayModel extends Component {
|
||||
return <span className="model">
|
||||
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
||||
[
|
||||
{
|
||||
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
|
||||
<br />{ key }: { String(v) }</span>)
|
||||
: null
|
||||
}
|
||||
{
|
||||
!description ? null :
|
||||
<Markdown source={ description } />
|
||||
}
|
||||
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
|
||||
]
|
||||
{
|
||||
properties.size ? <span>
|
||||
{ properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}>
|
||||
<br />{ key }: { String(v) }</span>)
|
||||
}<br /></span>
|
||||
: null
|
||||
}
|
||||
</ModelCollapse>
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -61,6 +61,13 @@ export default class LiveResponse extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
{ curlRequest && <Curl request={ curlRequest }/> }
|
||||
{ url && <div>
|
||||
<h4>Request URL</h4>
|
||||
<div className="request-url">
|
||||
<pre>{url}</pre>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<h4>Server response</h4>
|
||||
<table className="responses-table">
|
||||
<thead>
|
||||
|
||||
@@ -7,14 +7,19 @@ export default class ModelExample extends React.Component {
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
schema: PropTypes.object.isRequired,
|
||||
example: PropTypes.any.isRequired,
|
||||
isExecute: PropTypes.bool
|
||||
isExecute: PropTypes.bool,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
let { getConfigs } = this.props
|
||||
let { defaultModelRendering } = getConfigs()
|
||||
if (defaultModelRendering !== "example" && defaultModelRendering !== "model") {
|
||||
defaultModelRendering = "example"
|
||||
}
|
||||
this.state = {
|
||||
activeTab: "example"
|
||||
activeTab: defaultModelRendering
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +32,8 @@ export default class ModelExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let { getComponent, specSelectors, schema, example, isExecute } = this.props
|
||||
let { getComponent, specSelectors, schema, example, isExecute, getConfigs } = this.props
|
||||
let { defaultModelExpandDepth } = getConfigs()
|
||||
const ModelWrapper = getComponent("ModelWrapper")
|
||||
|
||||
return <div>
|
||||
@@ -47,7 +53,7 @@ export default class ModelExample extends React.Component {
|
||||
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
|
||||
getComponent={ getComponent }
|
||||
specSelectors={ specSelectors }
|
||||
expandDepth={ 1 } />
|
||||
expandDepth={ defaultModelExpandDepth } />
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export default class Models extends Component {
|
||||
render(){
|
||||
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
||||
let definitions = specSelectors.definitions()
|
||||
let { docExpansion } = getConfigs()
|
||||
let { docExpansion, defaultModelExpandDepth } = getConfigs()
|
||||
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
||||
|
||||
const ModelWrapper = getComponent("ModelWrapper")
|
||||
@@ -33,6 +33,7 @@ export default class Models extends Component {
|
||||
definitions.entrySeq().map( ( [ name, model ])=>{
|
||||
return <div className="model-container" key={ `models-section-${name}` }>
|
||||
<ModelWrapper name={ name }
|
||||
expandDepth={ defaultModelExpandDepth }
|
||||
schema={ model }
|
||||
getComponent={ getComponent }
|
||||
specSelectors={ specSelectors }/>
|
||||
|
||||
@@ -149,7 +149,7 @@ export default class Operation extends PureComponent {
|
||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
|
||||
|
||||
// Merge in Live Response
|
||||
if(response && response.size > 0) {
|
||||
if(responses && response && response.size > 0) {
|
||||
let notDocumented = !responses.get(String(response.get("status")))
|
||||
response = response.set("notDocumented", notDocumented)
|
||||
}
|
||||
@@ -224,6 +224,7 @@ export default class Operation extends PureComponent {
|
||||
specActions={ specActions }
|
||||
specSelectors={ specSelectors }
|
||||
pathMethod={ [path, method] }
|
||||
getConfigs={ getConfigs }
|
||||
/>
|
||||
|
||||
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
|
||||
|
||||
@@ -11,7 +11,8 @@ export default class ParameterRow extends Component {
|
||||
isExecute: PropTypes.bool,
|
||||
onChangeConsumes: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
pathMethod: PropTypes.array.isRequired
|
||||
pathMethod: PropTypes.array.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
@@ -30,7 +31,7 @@ export default class ParameterRow extends Component {
|
||||
let { specSelectors, pathMethod, param } = props
|
||||
let example = param.get("example")
|
||||
let defaultValue = param.get("default")
|
||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
|
||||
let paramValue = parameter ? parameter.get("value") : undefined
|
||||
let enumValue = parameter ? parameter.get("enum") : undefined
|
||||
let value
|
||||
@@ -56,7 +57,7 @@ export default class ParameterRow extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
||||
let {param, onChange, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
||||
|
||||
let { isOAS3 } = specSelectors
|
||||
|
||||
@@ -120,6 +121,7 @@ export default class ParameterRow extends Component {
|
||||
|
||||
{
|
||||
bodyParam && schema ? <ModelExample getComponent={ getComponent }
|
||||
getConfigs={ getConfigs }
|
||||
isExecute={ isExecute }
|
||||
specSelectors={ specSelectors }
|
||||
schema={ schema }
|
||||
|
||||
@@ -19,7 +19,8 @@ export default class Parameters extends Component {
|
||||
onTryoutClick: PropTypes.func,
|
||||
onCancelClick: PropTypes.func,
|
||||
onChangeKey: PropTypes.array,
|
||||
pathMethod: PropTypes.array.isRequired
|
||||
pathMethod: PropTypes.array.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +61,7 @@ export default class Parameters extends Component {
|
||||
|
||||
fn,
|
||||
getComponent,
|
||||
getConfigs,
|
||||
specSelectors,
|
||||
pathMethod
|
||||
} = this.props
|
||||
@@ -93,6 +95,7 @@ export default class Parameters extends Component {
|
||||
eachMap(parameters, (parameter) => (
|
||||
<ParameterRow fn={ fn }
|
||||
getComponent={ getComponent }
|
||||
getConfigs={ getConfigs }
|
||||
param={ parameter }
|
||||
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
|
||||
onChange={ this.onChange }
|
||||
|
||||
@@ -1,37 +1,40 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import Remarkable from "react-remarkable"
|
||||
import Remarkable from "remarkable"
|
||||
import sanitize from "sanitize-html"
|
||||
|
||||
function Markdown({ source }) {
|
||||
const sanitized = sanitizer(source)
|
||||
const html = new Remarkable({
|
||||
html: true,
|
||||
typographer: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
linkTarget: "_blank"
|
||||
}).render(source)
|
||||
const sanitized = sanitizer(html)
|
||||
|
||||
// sometimes the sanitizer returns "undefined" as a string
|
||||
if(!source || !sanitized || sanitized === "undefined") {
|
||||
return null
|
||||
}
|
||||
if ( !source || !html || !sanitized ) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div className="markdown">
|
||||
<Remarkable
|
||||
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={sanitized}
|
||||
></Remarkable>
|
||||
</div>
|
||||
return (
|
||||
<div className="markdown" dangerouslySetInnerHTML={{ __html: sanitized }}></div>
|
||||
)
|
||||
}
|
||||
|
||||
Markdown.propTypes = {
|
||||
source: PropTypes.string.isRequired
|
||||
source: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default Markdown
|
||||
|
||||
const sanitizeOptions = {
|
||||
textFilter: function(text) {
|
||||
return text
|
||||
.replace(/"/g, "\"")
|
||||
}
|
||||
allowedTags: sanitize.defaults.allowedTags.concat([ "img" ]),
|
||||
textFilter: function(text) {
|
||||
return text.replace(/"/g, "\"")
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizer(str) {
|
||||
return sanitize(str, sanitizeOptions)
|
||||
return sanitize(str, sanitizeOptions)
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ export default class ResponseBody extends React.Component {
|
||||
// Download
|
||||
} else if (
|
||||
/^application\/octet-stream/i.test(contentType) ||
|
||||
headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"]) ||
|
||||
headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"]) ||
|
||||
headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"]) ||
|
||||
headers["content-description"] && (/File Transfer/i).test(headers["content-description"])) {
|
||||
(headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"])) ||
|
||||
(headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"])) ||
|
||||
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
|
||||
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
|
||||
|
||||
let contentLength = headers["content-length"] || headers["Content-Length"]
|
||||
if ( !(+contentLength) ) return null
|
||||
|
||||
@@ -45,6 +45,7 @@ export default class Response extends React.Component {
|
||||
response: PropTypes.object,
|
||||
className: PropTypes.string,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
fn: PropTypes.object.isRequired,
|
||||
contentType: PropTypes.string,
|
||||
@@ -73,6 +74,7 @@ export default class Response extends React.Component {
|
||||
className,
|
||||
fn,
|
||||
getComponent,
|
||||
getConfigs,
|
||||
specSelectors,
|
||||
contentType,
|
||||
controlsAcceptHeader
|
||||
@@ -111,7 +113,7 @@ export default class Response extends React.Component {
|
||||
if(examples) {
|
||||
examples = examples.map(example => {
|
||||
// Remove unwanted properties from examples
|
||||
return example.set("$$ref", undefined)
|
||||
return example.set ? example.set("$$ref", undefined) : example
|
||||
})
|
||||
}
|
||||
|
||||
@@ -144,6 +146,7 @@ export default class Response extends React.Component {
|
||||
{ example ? (
|
||||
<ModelExample
|
||||
getComponent={ getComponent }
|
||||
getConfigs={ getConfigs }
|
||||
specSelectors={ specSelectors }
|
||||
schema={ fromJSOrdered(schema) }
|
||||
example={ example }/>
|
||||
|
||||
@@ -12,13 +12,13 @@ export default class Responses extends React.Component {
|
||||
produces: PropTypes.object,
|
||||
producesValue: PropTypes.any,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
specActions: PropTypes.object.isRequired,
|
||||
oas3Actions: PropTypes.object.isRequired,
|
||||
pathMethod: PropTypes.array.isRequired,
|
||||
displayRequestDuration: PropTypes.bool.isRequired,
|
||||
fn: PropTypes.object.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
fn: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
@@ -116,6 +116,7 @@ export default class Responses extends React.Component {
|
||||
controlsAcceptHeader={response === acceptControllingResponse}
|
||||
onContentTypeChange={this.onResponseContentTypeChange}
|
||||
contentType={ producesValue }
|
||||
getConfigs={ getConfigs }
|
||||
getComponent={ getComponent }/>
|
||||
)
|
||||
}).toArray()
|
||||
|
||||
@@ -45,6 +45,8 @@ module.exports = function SwaggerUI(opts) {
|
||||
requestInterceptor: (a => a),
|
||||
responseInterceptor: (a => a),
|
||||
showMutatedRequest: true,
|
||||
defaultModelRendering: "example",
|
||||
defaultModelExpandDepth: 1,
|
||||
|
||||
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
|
||||
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { createSelector } from "reselect"
|
||||
import { List } from "immutable"
|
||||
import { isOAS3 as isOAS3Helper } from "../helpers"
|
||||
|
||||
|
||||
// Helpers
|
||||
|
||||
function onlyOAS3(selector) {
|
||||
return (ori, system) => (...args) => {
|
||||
const spec = system.getSystem().specSelectors.specJson()
|
||||
if(isOAS3Helper(spec)) {
|
||||
return selector(...args)
|
||||
} else {
|
||||
return ori(...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nullSelector = createSelector(() => null)
|
||||
|
||||
const OAS3NullSelector = onlyOAS3(nullSelector)
|
||||
|
||||
// Hasta la vista, authentication!
|
||||
export const shownDefinitions = OAS3NullSelector
|
||||
export const definitionsToAuthorize = OAS3NullSelector
|
||||
export const getDefinitionsByNames = OAS3NullSelector
|
||||
export const authorized = onlyOAS3(() => List())
|
||||
export const isAuthorized = OAS3NullSelector
|
||||
export const getConfigs = OAS3NullSelector
|
||||
@@ -6,6 +6,7 @@ import { OrderedMap } from "immutable"
|
||||
const RequestBody = ({
|
||||
requestBody,
|
||||
getComponent,
|
||||
getConfigs,
|
||||
specSelectors,
|
||||
contentType,
|
||||
isExecute,
|
||||
@@ -27,6 +28,7 @@ const RequestBody = ({
|
||||
}
|
||||
<ModelExample
|
||||
getComponent={ getComponent }
|
||||
getConfigs={ getConfigs }
|
||||
specSelectors={ specSelectors }
|
||||
expandDepth={1}
|
||||
isExecute={isExecute}
|
||||
@@ -46,6 +48,7 @@ const RequestBody = ({
|
||||
RequestBody.propTypes = {
|
||||
requestBody: ImPropTypes.orderedMap.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
contentType: PropTypes.string.isRequired,
|
||||
isExecute: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// import reducers from "./reducers"
|
||||
// import * as actions from "./actions"
|
||||
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
|
||||
import * as authWrapSelectors from "./auth-extensions/wrap-selectors"
|
||||
import * as specSelectors from "./spec-extensions/selectors"
|
||||
import components from "./components"
|
||||
import wrapComponents from "./wrap-components"
|
||||
@@ -17,6 +18,9 @@ export default function() {
|
||||
wrapSelectors: specWrapSelectors,
|
||||
selectors: specSelectors
|
||||
},
|
||||
auth: {
|
||||
wrapSelectors: authWrapSelectors
|
||||
},
|
||||
oas3: {
|
||||
actions: oas3Actions,
|
||||
reducers: oas3Reducers,
|
||||
|
||||
@@ -53,6 +53,7 @@ export const basePath = OAS3NullSelector
|
||||
export const consumes = OAS3NullSelector
|
||||
export const produces = OAS3NullSelector
|
||||
export const schemes = OAS3NullSelector
|
||||
export const securityDefinitions = OAS3NullSelector
|
||||
|
||||
// New selectors
|
||||
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
import React from "react"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import { Parser, HtmlRenderer } from "commonmark"
|
||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||
import { sanitizer } from "core/components/providers/markdown"
|
||||
|
||||
export default OAS3ComponentWrapFactory(({ source }) => { return source ? (
|
||||
<ReactMarkdown
|
||||
source={sanitizer(source)}
|
||||
className={"renderedMarkdown"}
|
||||
/>
|
||||
) : null})
|
||||
export default OAS3ComponentWrapFactory(({ source }) => {
|
||||
if ( source ) {
|
||||
const parser = new Parser()
|
||||
const writer = new HtmlRenderer()
|
||||
const html = writer.render(parser.parse(source || ""))
|
||||
const sanitized = sanitizer(html)
|
||||
|
||||
if ( !source || !html || !sanitized ) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
source={sanitized}
|
||||
className={"renderedMarkdown"}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})
|
||||
@@ -470,6 +470,18 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|
||||
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
|
||||
}
|
||||
|
||||
export const validateMaximum = ( val, max ) => {
|
||||
if (val > max) {
|
||||
return "Value must be less than Maximum"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateMinimum = ( val, min ) => {
|
||||
if (val < min) {
|
||||
return "Value must be greater than Minimum"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateNumber = ( val ) => {
|
||||
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
|
||||
return "Value must be a number"
|
||||
@@ -512,13 +524,29 @@ export const validateGuid = (val) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const validateMaxLength = (val, max) => {
|
||||
if (val.length > max) {
|
||||
return "Value must be less than MaxLength"
|
||||
}
|
||||
}
|
||||
|
||||
export const validateMinLength = (val, min) => {
|
||||
if (val.length < min) {
|
||||
return "Value must be greater than MinLength"
|
||||
}
|
||||
}
|
||||
|
||||
// validation of parameters before execute
|
||||
export const validateParam = (param, isXml) => {
|
||||
let errors = []
|
||||
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
||||
let required = param.get("required")
|
||||
let maximum = param.get("maximum")
|
||||
let minimum = param.get("minimum")
|
||||
let type = param.get("type")
|
||||
let format = param.get("format")
|
||||
let maxLength = param.get("maxLength")
|
||||
let minLength = param.get("minLength")
|
||||
|
||||
/*
|
||||
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
||||
@@ -535,11 +563,31 @@ export const validateParam = (param, isXml) => {
|
||||
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
||||
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
||||
|
||||
if (maxLength || maxLength === 0) {
|
||||
let err = validateMaxLength(value, maxLength)
|
||||
if (err) errors.push(err)
|
||||
}
|
||||
|
||||
if (minLength) {
|
||||
let err = validateMinLength(value, minLength)
|
||||
if (err) errors.push(err)
|
||||
}
|
||||
|
||||
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
||||
errors.push("Required field is not provided")
|
||||
return errors
|
||||
}
|
||||
|
||||
if (maximum || maximum === 0) {
|
||||
let err = validateMaximum(value, maximum)
|
||||
if (err) errors.push(err)
|
||||
}
|
||||
|
||||
if (minimum || minimum === 0) {
|
||||
let err = validateMinimum(value, minimum)
|
||||
if (err) errors.push(err)
|
||||
}
|
||||
|
||||
if ( type === "string" ) {
|
||||
let err
|
||||
if (format === "date-time") {
|
||||
|
||||
@@ -252,8 +252,11 @@
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
flex: 0 3 auto;
|
||||
align-items: center;
|
||||
|
||||
word-break: break-all;
|
||||
|
||||
padding: 0 10px;
|
||||
|
||||
@include text_code();
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { shallow } from "enzyme"
|
||||
import ModelExample from "components/model-example"
|
||||
import ModelComponent from "components/model-wrapper"
|
||||
|
||||
describe("<ModelExample/>", function(){
|
||||
// Given
|
||||
let components = {
|
||||
ModelWrapper: ModelComponent
|
||||
}
|
||||
let props = {
|
||||
getComponent: (c) => {
|
||||
return components[c]
|
||||
},
|
||||
specSelectors: {},
|
||||
schema: {},
|
||||
example: "{\"example\": \"value\"}",
|
||||
isExecute: false,
|
||||
getConfigs: () => ({
|
||||
defaultModelRendering: "model",
|
||||
defaultModelExpandDepth: 1
|
||||
})
|
||||
}
|
||||
let exampleSelectedTestInputs = [
|
||||
{ defaultModelRendering: "model", isExecute: true },
|
||||
{ defaultModelRendering: "example", isExecute: true },
|
||||
{ defaultModelRendering: "example", isExecute: false },
|
||||
{ defaultModelRendering: "othervalue", isExecute: true },
|
||||
{ defaultModelRendering: "othervalue", isExecute: false }
|
||||
]
|
||||
let modelSelectedTestInputs = [
|
||||
{ defaultModelRendering: "model", isExecute: false }
|
||||
]
|
||||
|
||||
|
||||
it("renders model and example tabs", function(){
|
||||
// When
|
||||
let wrapper = shallow(<ModelExample {...props}/>)
|
||||
|
||||
// Then should render tabs
|
||||
expect(wrapper.find("div > ul.tab").length).toEqual(1)
|
||||
|
||||
let tabs = wrapper.find("div > ul.tab").children()
|
||||
expect(tabs.length).toEqual(2)
|
||||
tabs.forEach((node) => {
|
||||
expect(node.length).toEqual(1)
|
||||
expect(node.name()).toEqual("li")
|
||||
expect(node.hasClass("tabitem")).toEqual(true)
|
||||
})
|
||||
expect(tabs.at(0).text()).toEqual("Example Value")
|
||||
expect(tabs.at(1).text()).toEqual("Model")
|
||||
})
|
||||
|
||||
exampleSelectedTestInputs.forEach(function(testInputs) {
|
||||
it("example tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||
// When
|
||||
props.isExecute = testInputs.isExecute
|
||||
props.getConfigs = () => ({
|
||||
defaultModelRendering: testInputs.defaultModelRendering,
|
||||
defaultModelExpandDepth: 1
|
||||
})
|
||||
let wrapper = shallow(<ModelExample {...props}/>)
|
||||
|
||||
// Then
|
||||
let tabs = wrapper.find("div > ul.tab").children()
|
||||
|
||||
let exampleTab = tabs.at(0)
|
||||
expect(exampleTab.hasClass("active")).toEqual(true)
|
||||
let modelTab = tabs.at(1)
|
||||
expect(modelTab.hasClass("active")).toEqual(false)
|
||||
|
||||
expect(wrapper.find("div > div").length).toEqual(1)
|
||||
expect(wrapper.find("div > div").text()).toEqual(props.example)
|
||||
})
|
||||
})
|
||||
|
||||
modelSelectedTestInputs.forEach(function(testInputs) {
|
||||
it("model tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
|
||||
// When
|
||||
props.isExecute = testInputs.isExecute
|
||||
props.getConfigs = () => ({
|
||||
defaultModelRendering: testInputs.defaultModelRendering,
|
||||
defaultModelExpandDepth: 1
|
||||
})
|
||||
let wrapper = shallow(<ModelExample {...props}/>)
|
||||
|
||||
// Then
|
||||
let tabs = wrapper.find("div > ul.tab").children()
|
||||
|
||||
let exampleTab = tabs.at(0)
|
||||
expect(exampleTab.hasClass("active")).toEqual(false)
|
||||
let modelTab = tabs.at(1)
|
||||
expect(modelTab.hasClass("active")).toEqual(true)
|
||||
|
||||
expect(wrapper.find("div > div").length).toEqual(1)
|
||||
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
it("passes defaultModelExpandDepth to ModelComponent", function(){
|
||||
// When
|
||||
let expandDepth = 0
|
||||
props.isExecute = false
|
||||
props.getConfigs = () => ({
|
||||
defaultModelRendering: "model",
|
||||
defaultModelExpandDepth: expandDepth
|
||||
})
|
||||
let wrapper = shallow(<ModelExample {...props}/>)
|
||||
|
||||
// Then
|
||||
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(expandDepth)
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,51 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect, { createSpy } from "expect"
|
||||
import { shallow } from "enzyme"
|
||||
import { fromJS } from "immutable"
|
||||
import Models from "components/models"
|
||||
import ModelCollpase from "components/model-collapse"
|
||||
import ModelComponent from "components/model-wrapper"
|
||||
|
||||
describe("<Models/>", function(){
|
||||
// Given
|
||||
let components = {
|
||||
Collapse: ModelCollpase,
|
||||
ModelWrapper: ModelComponent
|
||||
}
|
||||
let props = {
|
||||
getComponent: (c) => {
|
||||
return components[c]
|
||||
},
|
||||
specSelectors: {
|
||||
definitions: function() {
|
||||
return fromJS({
|
||||
def1: {},
|
||||
def2: {}
|
||||
})
|
||||
}
|
||||
},
|
||||
layoutSelectors: {
|
||||
isShown: createSpy()
|
||||
},
|
||||
layoutActions: {},
|
||||
getConfigs: () => ({
|
||||
docExpansion: "list",
|
||||
defaultModelExpandDepth: 0
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
it("passes defaultModelExpandDepth to ModelWrapper", function(){
|
||||
// When
|
||||
let wrapper = shallow(<Models {...props}/>)
|
||||
|
||||
// Then should render tabs
|
||||
expect(wrapper.find("ModelCollapse").length).toEqual(1)
|
||||
expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0)
|
||||
wrapper.find("ModelComponent").forEach((modelWrapper) => {
|
||||
expect(modelWrapper.props().expandDepth).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
+156
-4
@@ -1,7 +1,23 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import { fromJS, OrderedMap } from "immutable"
|
||||
import { mapToList, validateDateTime, validateGuid, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered, getAcceptControllingResponse, createDeepLinkPath, escapeDeepLinkPath } from "core/utils"
|
||||
import {
|
||||
mapToList,
|
||||
validateMinLength,
|
||||
validateMaxLength,
|
||||
validateDateTime,
|
||||
validateGuid,
|
||||
validateNumber,
|
||||
validateInteger,
|
||||
validateParam,
|
||||
validateFile,
|
||||
validateMaximum,
|
||||
validateMinimum,
|
||||
fromJSOrdered,
|
||||
getAcceptControllingResponse,
|
||||
createDeepLinkPath,
|
||||
escapeDeepLinkPath
|
||||
} from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
describe("utils", function() {
|
||||
@@ -72,6 +88,36 @@ describe("utils", function() {
|
||||
|
||||
})
|
||||
|
||||
describe("validateMaximum", function() {
|
||||
let errorMessage = "Value must be less than Maximum"
|
||||
|
||||
it("doesn't return for valid input", function() {
|
||||
expect(validateMaximum(9, 10)).toBeFalsy()
|
||||
expect(validateMaximum(19, 20)).toBeFalsy()
|
||||
})
|
||||
|
||||
it("returns a message for invalid input", function() {
|
||||
expect(validateMaximum(1, 0)).toEqual(errorMessage)
|
||||
expect(validateMaximum(10, 9)).toEqual(errorMessage)
|
||||
expect(validateMaximum(20, 19)).toEqual(errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateMinimum", function() {
|
||||
let errorMessage = "Value must be greater than Minimum"
|
||||
|
||||
it("doesn't return for valid input", function() {
|
||||
expect(validateMinimum(2, 1)).toBeFalsy()
|
||||
expect(validateMinimum(20, 10)).toBeFalsy()
|
||||
})
|
||||
|
||||
it("returns a message for invalid input", function() {
|
||||
expect(validateMinimum(-1, 0)).toEqual(errorMessage)
|
||||
expect(validateMinimum(1, 2)).toEqual(errorMessage)
|
||||
expect(validateMinimum(10, 20)).toEqual(errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateNumber", function() {
|
||||
let errorMessage = "Value must be a number"
|
||||
|
||||
@@ -198,6 +244,35 @@ describe("utils", function() {
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateMaxLength", function() {
|
||||
let errorMessage = "Value must be less than MaxLength"
|
||||
|
||||
it("doesn't return for valid guid", function() {
|
||||
expect(validateMaxLength("a", 1)).toBeFalsy()
|
||||
expect(validateMaxLength("abc", 5)).toBeFalsy()
|
||||
})
|
||||
|
||||
it("returns a message for invalid input'", function() {
|
||||
expect(validateMaxLength("abc", 0)).toEqual(errorMessage)
|
||||
expect(validateMaxLength("abc", 1)).toEqual(errorMessage)
|
||||
expect(validateMaxLength("abc", 2)).toEqual(errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateMinLength", function() {
|
||||
let errorMessage = "Value must be greater than MinLength"
|
||||
|
||||
it("doesn't return for valid guid", function() {
|
||||
expect(validateMinLength("a", 1)).toBeFalsy()
|
||||
expect(validateMinLength("abc", 2)).toBeFalsy()
|
||||
})
|
||||
|
||||
it("returns a message for invalid input'", function() {
|
||||
expect(validateMinLength("abc", 5)).toEqual(errorMessage)
|
||||
expect(validateMinLength("abc", 8)).toEqual(errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe("validateParam", function() {
|
||||
let param = null
|
||||
let result = null
|
||||
@@ -223,7 +298,7 @@ describe("utils", function() {
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Required field is not provided"] )
|
||||
|
||||
// valid string
|
||||
// valid string
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "string",
|
||||
@@ -231,6 +306,50 @@ describe("utils", function() {
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( [] )
|
||||
|
||||
// valid string with min and max length
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "string",
|
||||
value: "test string",
|
||||
maxLength: 50,
|
||||
minLength: 1
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( [] )
|
||||
})
|
||||
|
||||
it("validates required strings with min and max length", function() {
|
||||
// invalid string with max length
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "string",
|
||||
value: "test string",
|
||||
maxLength: 5
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Value must be less than MaxLength"] )
|
||||
|
||||
// invalid string with max length 0
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "string",
|
||||
value: "test string",
|
||||
maxLength: 0
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Value must be less than MaxLength"] )
|
||||
|
||||
|
||||
// invalid string with min length
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "string",
|
||||
value: "test string",
|
||||
minLength: 50
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Value must be greater than MinLength"] )
|
||||
})
|
||||
|
||||
it("validates optional strings", function() {
|
||||
@@ -485,14 +604,47 @@ describe("utils", function() {
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Required field is not provided"] )
|
||||
|
||||
// valid number
|
||||
// valid number with min and max
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "number",
|
||||
value: 10
|
||||
value: 10,
|
||||
minimum: 5,
|
||||
maximum: 99
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( [] )
|
||||
|
||||
// valid negative number with min and max
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "number",
|
||||
value: -10,
|
||||
minimum: -50,
|
||||
maximum: -5
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( [] )
|
||||
|
||||
// invalid number with maximum:0
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "number",
|
||||
value: 1,
|
||||
maximum: 0
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Value must be less than Maximum"] )
|
||||
|
||||
// invalid number with minimum:0
|
||||
param = fromJS({
|
||||
required: true,
|
||||
type: "number",
|
||||
value: -10,
|
||||
minimum: 0
|
||||
})
|
||||
result = validateParam( param, false )
|
||||
expect( result ).toEqual( ["Value must be greater than Minimum"] )
|
||||
})
|
||||
|
||||
it("validates optional numbers", function() {
|
||||
|
||||
Reference in New Issue
Block a user