Merge branch 'master' into bug/3480-model-description-over-the-edge

This commit is contained in:
Kyle
2017-08-04 16:23:50 -07:00
committed by GitHub
17 changed files with 159 additions and 42 deletions

View File

@@ -18,16 +18,17 @@ This repo publishes to two different NPM packages:
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x). 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 4 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 | Status Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | ----- | ------ ------------------ | ------------ | -------------------------- | -----
3.1.1 | 2017-07-29 | 2.0 | [tag v3.1.1](https://github.com/swagger-api/swagger-ui/tree/v3.1.1) | 3.1.2 | 2017-07-31 | 2.0, 3.0 | [tag v3.1.2](https://github.com/swagger-api/swagger-ui/tree/v3.1.2)
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) | 3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
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.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.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) | 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)
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13) | 2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24)
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1) | 1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13)
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1)
### How to run ### How to run
@@ -96,7 +97,8 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui
#### OAuth2 configuration #### OAuth2 configuration
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle` You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`. default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
`useBasicAuthenticationWithAccessCodeGrant`.
Config Name | Description Config Name | Description
--- | --- --- | ---
@@ -106,6 +108,7 @@ realm | realm query parameter (for oauth1) added to `authorizationUrl` and `toke
appName | application name, displayed in authorization popup. MUST be a string appName | application name, displayed in authorization popup. MUST be a string
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object 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`
``` ```
const ui = SwaggerUIBundle({...}) const ui = SwaggerUIBundle({...})
@@ -135,6 +138,7 @@ urls.primaryName | When using `urls`, you can use this subparameter. If the valu
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them. spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
domNode | The HTML DOM element inside which SwaggerUi will put the user interface for swagger. Overrides `dom_id`.
oauth2RedirectUrl | OAuth redirect URL 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. 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. 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.

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAoyKA;;;;;;AAy+EA;;;;;;;;;;;;;;;;;;;;;;;;;;AA00TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AA+5oBA;;;;;AA2lQA;AAm4DA;;;;;;AAo4YA;;;;;;AA0iaA;AAumvBA","sourceRoot":""} {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAoyKA;;;;;;AAy+EA;;;;;;;;;;;;;;;;;;;;;;;;;;AAw1TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAy6oBA;;;;;AAqqQA;AAm4DA;;;;;;AAo4YA;;;;;;AA8jaA;AAumvBA","sourceRoot":""}

File diff suppressed because one or more lines are too long

4
dist/swagger-ui.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAwpcA","sourceRoot":""} {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAyvcA","sourceRoot":""}

View File

@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.1.1", "version": "3.1.2",
"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": [
@@ -43,7 +43,6 @@
"ieee754": "^1.1.8", "ieee754": "^1.1.8",
"immutable": "^3.x.x", "immutable": "^3.x.x",
"js-yaml": "^3.5.5", "js-yaml": "^3.5.5",
"less": "2.7.1",
"lodash": "4.17.2", "lodash": "4.17.2",
"matcher": "^0.1.2", "matcher": "^0.1.2",
"memoizee": "0.4.1", "memoizee": "0.4.1",

View File

@@ -18,7 +18,8 @@ export default class ObjectModel extends Component {
render(){ render(){
let { schema, name, isRef, getComponent, depth, ...props } = this.props let { schema, name, isRef, getComponent, depth, ...props } = this.props
let { expandDepth } = this.props let { expandDepth, specSelectors } = this.props
let { isOAS3 } = specSelectors
let description = schema.get("description") let description = schema.get("description")
let properties = schema.get("properties") let properties = schema.get("properties")
let additionalProperties = schema.get("additionalProperties") let additionalProperties = schema.get("additionalProperties")
@@ -30,14 +31,21 @@ export default class ObjectModel extends Component {
const Model = getComponent("Model") const Model = getComponent("Model")
const ModelCollapse = getComponent("ModelCollapse") const ModelCollapse = getComponent("ModelCollapse")
const JumpToPathSection = ({ name }) => <span className="model-jump-to-path"><JumpToPath path={`definitions.${name}`} /></span> const JumpToPathSection = ({ name }) => {
const path = isOAS3 && isOAS3() ? `components.schemas.${name}` : `definitions.${name}`
return <span className="model-jump-to-path"><JumpToPath path={path} /></span>
}
const collapsedContent = (<span> const collapsedContent = (<span>
<span>{ braceOpen }</span>...<span>{ braceClose }</span> <span>{ braceOpen }</span>...<span>{ braceClose }</span>
{ {
isRef ? <JumpToPathSection name={ name }/> : "" isRef ? <JumpToPathSection name={ name }/> : ""
} }
</span>) </span>)
const anyOf = specSelectors.isOAS3() ? schema.get("anyOf") : null
const oneOf = specSelectors.isOAS3() ? schema.get("oneOf") : null
const not = specSelectors.isOAS3() ? schema.get("not") : null
const titleEl = title && <span className="model-title"> const titleEl = title && <span className="model-title">
{ isRef && schema.get("$$ref") && <span className="model-hint">{ schema.get("$$ref") }</span> } { isRef && schema.get("$$ref") && <span className="model-hint">{ schema.get("$$ref") }</span> }
<span className="model-title__text">{ title }</span> <span className="model-title__text">{ title }</span>
@@ -95,6 +103,48 @@ export default class ObjectModel extends Component {
</td> </td>
</tr> </tr>
} }
{
!anyOf ? null
: <tr>
<td>{ "anyOf ->" }</td>
<td>
{anyOf.map((schema, k) => {
return <div key={k}><Model { ...props } required={ false }
getComponent={ getComponent }
schema={ schema }
depth={ depth + 1 } /></div>
})}
</td>
</tr>
}
{
!oneOf ? null
: <tr>
<td>{ "oneOf ->" }</td>
<td>
{oneOf.map((schema, k) => {
return <div key={k}><Model { ...props } required={ false }
getComponent={ getComponent }
schema={ schema }
depth={ depth + 1 } /></div>
})}
</td>
</tr>
}
{
!not ? null
: <tr>
<td>{ "not ->" }</td>
<td>
{not.map((schema, k) => {
return <div key={k}><Model { ...props } required={ false }
getComponent={ getComponent }
schema={ schema }
depth={ depth + 1 } /></div>
})}
</td>
</tr>
}
</tbody></table> </tbody></table>
} }
</span> </span>
@@ -102,4 +152,4 @@ export default class ObjectModel extends Component {
</ModelCollapse> </ModelCollapse>
</span> </span>
} }
} }

View File

@@ -186,7 +186,7 @@ export default class Operation extends PureComponent {
} }
</div> </div>
<Collapse isOpened={shown} animated> <Collapse isOpened={shown}>
<div className="opblock-body"> <div className="opblock-body">
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>} { deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
{ description && { description &&

View File

@@ -66,6 +66,8 @@ export default class Operations extends React.Component {
taggedOps.map( (tagObj, tag) => { taggedOps.map( (tagObj, tag) => {
let operations = tagObj.get("operations") let operations = tagObj.get("operations")
let tagDescription = tagObj.getIn(["tagDetails", "description"], null) 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", tag] let isShownKey = ["operations-tag", tag]
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list") let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
@@ -89,6 +91,22 @@ export default class Operations extends React.Component {
</small> </small>
} }
<div>
{ !tagExternalDocsDescription ? null :
<small>
{ tagExternalDocsDescription }
{ tagExternalDocsUrl ? ": " : null }
{ tagExternalDocsUrl ?
<a
href={tagExternalDocsUrl}
onClick={(e) => e.stopPropagation()}
target={"_blank"}
>{tagExternalDocsUrl}</a> : null
}
</small>
}
</div>
<button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}> <button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}>
<svg className="arrow" width="20" height="20"> <svg className="arrow" width="20" height="20">
<use xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} /> <use xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />

View File

@@ -58,6 +58,8 @@ export default class ParameterRow extends Component {
render() { render() {
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
let { isOAS3 } = specSelectors
// const onChangeWrapper = (value) => onChange(param, value) // const onChangeWrapper = (value) => onChange(param, value)
const JsonSchemaForm = getComponent("JsonSchemaForm") const JsonSchemaForm = getComponent("JsonSchemaForm")
const ParamBody = getComponent("ParamBody") const ParamBody = getComponent("ParamBody")
@@ -95,6 +97,9 @@ export default class ParameterRow extends Component {
{ !required ? null : <span style={{color: "red"}}>&nbsp;*</span> } { !required ? null : <span style={{color: "red"}}>&nbsp;*</span> }
</div> </div>
<div className="parameter__type">{ param.get("type") } { itemType && `[${itemType}]` }</div> <div className="parameter__type">{ param.get("type") } { itemType && `[${itemType}]` }</div>
<div className="parameter__deprecated">
{ isOAS3 && isOAS3() && param.get("deprecated") ? "deprecated": null }
</div>
<div className="parameter__in">({ param.get("in") })</div> <div className="parameter__in">({ param.get("in") })</div>
</td> </td>

View File

@@ -86,8 +86,8 @@ export default class Response extends React.Component {
sampleResponse = oas3SchemaForContentType ? getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, { includeReadOnly: true }) : null sampleResponse = oas3SchemaForContentType ? getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, { includeReadOnly: true }) : null
schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null
} else { } else {
sampleResponse = schema ? getSampleSchema(schema, contentType, { includeReadOnly: true }) : null
schema = inferSchema(response.toJS()) schema = inferSchema(response.toJS())
sampleResponse = schema ? getSampleSchema(schema, contentType, { includeReadOnly: true }) : null
} }
let example = getExampleComponent( sampleResponse, examples, HighlightCode ) let example = getExampleComponent( sampleResponse, examples, HighlightCode )

View File

@@ -23,6 +23,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,
domNode: null,
spec: {}, spec: {},
url: "", url: "",
urls: null, urls: null,
@@ -99,6 +100,12 @@ module.exports = function SwaggerUI(opts) {
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)
// deep extend mangles domNode, we need to set it manually
if(opts.domNode) {
mergedConfig.domNode = opts.domNode
}
store.setConfigs(mergedConfig) store.setConfigs(mergedConfig)
if (fetchedConfig !== null) { if (fetchedConfig !== null) {
@@ -112,10 +119,13 @@ module.exports = function SwaggerUI(opts) {
} }
} }
if(mergedConfig.dom_id) { if(mergedConfig.domNode) {
system.render(mergedConfig.dom_id, "App") system.render(mergedConfig.domNode, "App")
} else if(mergedConfig.dom_id) {
let domNode = document.querySelector(mergedConfig.dom_id)
system.render(domNode, "App")
} else { } else {
console.error("Skipped rendering: no `dom_id` was specified") console.error("Skipped rendering: no `dom_id` or `domNode` was specified")
} }
return system return system

View File

@@ -68,11 +68,21 @@ export default function authorize ( { auth, authActions, errActions, configs, au
// pass action authorizeOauth2 and authentication data through window // pass action authorizeOauth2 and authentication data through window
// to authorize with oauth2 // to authorize with oauth2
let callback
if (flow === "implicit") {
callback = authActions.preAuthorizeImplicit
} else if (authConfigs.useBasicAuthenticationWithAccessCodeGrant) {
callback = authActions.authorizeAccessCodeWithBasicAuthentication
} else {
callback = authActions.authorizeAccessCodeWithFormParams
}
win.swaggerUIRedirectOauth2 = { win.swaggerUIRedirectOauth2 = {
auth: auth, auth: auth,
state: state, state: state,
redirectUrl: redirectUrl, redirectUrl: redirectUrl,
callback: flow === "implicit" ? authActions.preAuthorizeImplicit : authActions.authorizeAccessCode, callback: callback,
errCb: errActions.newAuthErr errCb: errActions.newAuthErr
} }

View File

@@ -111,7 +111,7 @@ export const authorizeApplication = ( auth ) => ( { authActions } ) => {
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers }) return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers })
} }
export const authorizeAccessCode = ( { auth, redirectUrl } ) => ( { authActions } ) => { export const authorizeAccessCodeWithFormParams = ( { auth, redirectUrl } ) => ( { authActions } ) => {
let { schema, name, clientId, clientSecret } = auth let { schema, name, clientId, clientSecret } = auth
let form = { let form = {
grant_type: "authorization_code", grant_type: "authorization_code",
@@ -124,6 +124,21 @@ export const authorizeAccessCode = ( { auth, redirectUrl } ) => ( { authActions
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth}) return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
} }
export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl } ) => ( { authActions } ) => {
let { schema, name, clientId, clientSecret } = auth
let headers = {
Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
}
let form = {
grant_type: "authorization_code",
code: auth.code,
client_id: clientId,
redirect_uri: redirectUrl
}
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers})
}
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => { export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => {
let { body, query={}, headers={}, name, url, auth } = data let { body, query={}, headers={}, name, url, auth } = data
let { additionalQueryStringParams } = authSelectors.getConfigs() || {} let { additionalQueryStringParams } = authSelectors.getConfigs() || {}
@@ -135,7 +150,6 @@ export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, aut
let _headers = Object.assign({ let _headers = Object.assign({
"Accept":"application/json, text/plain, */*", "Accept":"application/json, text/plain, */*",
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/x-www-form-urlencoded" "Content-Type": "application/x-www-form-urlencoded"
}, headers) }, headers)

View File

@@ -58,8 +58,7 @@ export const makeMappedContainer = (getSystem, getStore, memGetComponent, getCom
} }
export const render = (getSystem, getStore, getComponent, getComponents, dom) => { export const render = (getSystem, getStore, getComponent, getComponents, domNode) => {
let domNode = document.querySelector(dom)
let App = (getComponent(getSystem, getStore, getComponents, "App", "root")) let App = (getComponent(getSystem, getStore, getComponents, "App", "root"))
ReactDOM.render(( <App/> ), domNode) ReactDOM.render(( <App/> ), domNode)
} }

View File

@@ -138,6 +138,14 @@ table
@include text_code(#888); @include text_code(#888);
} }
.parameter__deprecated
{
font-size: 12px;
font-style: italic;
@include text_code(#f00);
}
.table-container .table-container
{ {