Compare commits

...
9 Commits
Author SHA1 Message Date
kyle 49e0466641 v3.12.1 (#4311)
* v3.12.1

* Rebuild dist for v3.12.1
2018-03-09 20:54:22 -08:00
Helder Sepulveda ad57f5a549 Add empty div (#4236)
if there are properties show an empty div
2018-03-08 17:46:21 -08:00
Helder Sepulveda ebf94dfccf Allow images with data scheme (#4305)
* Add UnitTest for images

allows image elements with https scheme

* Test images with data scheme

* Add allowedSchemesByTag

* Fix error  Strings must use doublequote  quotes
2018-03-08 17:17:30 -08:00
Helder Sepulveda 6ba93ad43f improve: hide loading validator image (#4287)
* hide missing validator image

* Render nothing if validator badge has not loaded/received errors

* Revert style changes
2018-03-06 21:43:06 -08:00
kyle 54153dd929 remove docker login email param (#4283) 2018-03-02 22:22:39 -08:00
kyle 83232dc2d8 v3.12.0 (#4282)
* Use `parameterWithMeta` to get parameter data in <ParameterRow>

* Prefer specPath when fetching resolved subtrees in OperationContainer

* Add test for OAS3 callback rendering

* Remove debugger statement

* Pass base resolution URL directly to Swagger-Client subtree resolver

* Remove accidental comment

* Migrate additional options

* Don't default to empty Map when getting subtree

* fix(validateParam): check for ImList type before using count method

* Use `replaceState` to update `urls.primaryName`

This gives us the stateful URL we want, without:
(a) refreshing the page on update
(b) creating a long, useless history for the user
(c) implying that browser history is two-way bound
    to Swagger-UI (it isn't, we don't have a router)

* Add `fn.opsFilter` docs and internal API versioning note

* restrict `x-example` functionality to Swagger 2.0

* polish Authorize + Close buttons

* add tachyons; use it for padding the new Reset button

* v3.12.0

* rebuild dist
2018-03-02 21:13:00 -08:00
russell ad43965d16 improve: add button to reset example when user modifies request body (#4185)
* Add a button to reset example when user modifys request body

* lint fixes

* Revert "lint fixes"

This reverts commit 5395005ea7.

* reapply lint fixes
2018-03-02 18:46:47 -08:00
Charles Capps 861cc65cff improve: add "Close" button to OAuth dialog, rename "Done" button elsewhere (#4212)
* Rename "Done" button to "Close", and add "Close" button OAuth dialog
* move Close button to the right
2018-03-02 18:40:54 -08:00
Davide Zipeto 4900b11079 feature: read the x-example field and use them as values (#3538)
* Read the x-example field and use them as values
Allow to show the value defined in the "x-example" field when pressing try-out. The "default" value will have the precedence over the x-example

* Use `parameterWithMeta` to get parameter data in <ParameterRow>
* Prefer specPath when fetching resolved subtrees in OperationContainer
* Add test for OAS3 callback rendering
* Remove debugger statement
* Pass base resolution URL directly to Swagger-Client subtree resolver
* Remove accidental comment
* Migrate additional options
* Don't default to empty Map when getting subtree
* make "default" and "x-example" mutually exclusive
"x-example" wins when both are present
* limit "x-example" to non-body parameters
2018-03-02 18:31:08 -08:00
24 changed files with 162 additions and 50 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ deploy:
node: '6.9'
after_success:
- if [ $DOCKER_HUB_USERNAME ]; then
docker login --email=$DOCKER_HUB_EMAIL --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD;
docker login --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD;
if [ ! -z "$TRAVIS_TAG" ]; then
DOCKER_IMAGE_TAG=$TRAVIS_TAG;
+1 -1
View File
@@ -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.11.0 | 2018-02-09 | 2.0, 3.0 | [tag v3.11.0](https://github.com/swagger-api/swagger-ui/tree/v3.11.0)
3.12.1 | 2018-03-09 | 2.0, 3.0 | [tag v3.12.1](https://github.com/swagger-api/swagger-ui/tree/v3.12.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)
+14 -20
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+43
View File
@@ -0,0 +1,43 @@
# Plug points
Swagger-UI exposes most of its internal logic through the plugin system.
Often, it is beneficial to override the core internals to achieve custom behavior.
### Note: Semantic Versioning
Swagger-UI's internal APIs are _not_ part of our public contract, which means that they can change without the major version changing.
If your custom plugins wrap, extend, override, or consume any internal core APIs, we recommend specifying a specific minor version of Swagger-UI to use in your application, because they will _not_ change between patch versions.
If you're installing Swagger-UI via NPM, for example, you can do this by using a tilde:
```js
{
"dependencies": {
"swagger-ui": "~3.11.0"
}
}
```
### `fn.opsFilter`
When using the `filter` option, tag names will be filtered by the user-provided value. If you'd like to customize this behavior, you can override the default `opsFilter` function.
For example, you can implement a multiple-phrase filter:
```js
const MultiplePhraseFilterPlugin = function() {
return {
fn: {
opsFilter: (taggedOps, phrase) => {
const phrases = phrase.split(", ")
return taggedOps.filter((val, key) => {
return phrases.some(item => key.indexOf(item) > -1)
})
}
}
}
}
```
+16
View File
@@ -2,6 +2,22 @@
A plugin is a function that returns an object - more specifically, the object may contain functions and components that augment and modify Swagger-UI's functionality.
### Note: Semantic Versioning
Swagger-UI's internal APIs are _not_ part of our public contract, which means that they can change without the major version changing.
If your custom plugins wrap, extend, override, or consume any internal core APIs, we recommend specifying a specific minor version of Swagger-UI to use in your application, because they will _not_ change between patch versions.
If you're installing Swagger-UI via NPM, for example, you can do this by using a tilde:
```js
{
"dependencies": {
"swagger-ui": "~3.11.0"
}
}
```
### Format
A plugin return value may contain any of these keys, where `stateKey` is a name for a piece of state:
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.11.0",
"version": "3.12.1",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -83,7 +83,7 @@
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.5.0",
"swagger-client": "^3.5.1",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
@@ -144,6 +144,7 @@
"standard": "^10.0.2",
"standard-loader": "^6.0.1",
"style-loader": "0.18.2",
"tachyons-sass": "^4.9.2",
"url-loader": "0.5.9",
"webpack": "^2.6.1",
"webpack-bundle-size-analyzer": "^2.5.0"
+1 -1
View File
@@ -46,7 +46,7 @@ export default class ArrayModel extends Component {
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null
}
{
!description ? null :
!description ? (properties.size ? <div className="markdown"></div> : null) :
<Markdown source={ description } />
}
<span>
+1 -1
View File
@@ -81,11 +81,11 @@ export default class Auths extends React.Component {
}).toArray()
}
<div className="auth-btn-wrapper">
<Button className="btn modal-btn auth btn-done" onClick={ this.close }>Done</Button>
{
nonOauthDefinitions.size === authorizedAuth.size ? <Button className="btn modal-btn auth" onClick={ this.logoutClick }>Logout</Button>
: <Button type="submit" className="btn modal-btn auth authorize">Authorize</Button>
}
<Button className="btn modal-btn auth btn-done" onClick={ this.close }>Close</Button>
</div>
</form>
}
+8
View File
@@ -39,6 +39,13 @@ export default class Oauth2 extends React.Component {
}
}
close = (e) => {
e.preventDefault()
let { authActions } = this.props
authActions.showDefinitions(false)
}
authorize =() => {
let { authActions, errActions, getConfigs, authSelectors } = this.props
let configs = getConfigs()
@@ -231,6 +238,7 @@ export default class Oauth2 extends React.Component {
: <Button className="btn modal-btn auth authorize" onClick={ this.authorize }>Authorize</Button>
)
}
<Button className="btn modal-btn auth btn-done" onClick={ this.close }>Close</Button>
</div>
</div>
@@ -101,7 +101,7 @@ class ValidatorImage extends React.Component {
if (this.state.error) {
return <img alt={"Error"} />
} else if (!this.state.loaded) {
return <img alt= {"Loading..."} />
return null
}
return <img src={this.props.src} alt={this.props.alt} />
}
+9 -2
View File
@@ -24,11 +24,18 @@ export default class ParameterRow extends Component {
let { specSelectors, pathMethod, param } = props
let defaultValue = param.get("default")
let xExampleValue = param.get("x-example")
let parameter = specSelectors.parameterWithMeta(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : ""
if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
if( param.get("in") !== "body" ) {
if ( xExampleValue !== undefined && value === undefined && specSelectors.isSwagger2() ) {
this.onChangeWrapper(xExampleValue)
} else if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
}
}
}
componentWillReceiveProps(props) {
@@ -46,6 +46,7 @@ const sanitizeOptions = {
"td": [ "colspan" ],
"*": [ "class" ]
},
allowedSchemesByTag: { img: [ "http", "https", "data" ] },
textFilter: function(text) {
return text.replace(/&quot;/g, "\"")
}
@@ -27,6 +27,7 @@ export default class RequestBodyEditor extends PureComponent {
this.state = {
isEditBox: false,
userDidModify: false,
value: ""
}
}
@@ -59,6 +60,11 @@ export default class RequestBodyEditor extends PureComponent {
this.onChange(this.sample(explicitMediaType))
}
resetValueToSample = (explicitMediaType) => {
this.setState({ userDidModify: false })
this.setValueToSample(explicitMediaType)
}
sample = (explicitMediaType) => {
let { requestBody, mediaType } = this.props
let schema = requestBody.getIn(["content", explicitMediaType || mediaType, "schema"]).toJS()
@@ -78,6 +84,7 @@ export default class RequestBodyEditor extends PureComponent {
const isJson = /json/i.test(mediaType)
const inputValue = isJson ? e.target.value.trim() : e.target.value
this.setState({ userDidModify: true })
this.onChange(inputValue)
}
@@ -87,13 +94,14 @@ export default class RequestBodyEditor extends PureComponent {
let {
isExecute,
getComponent,
mediaType,
} = this.props
const Button = getComponent("Button")
const TextArea = getComponent("TextArea")
const HighlightCode = getComponent("highlightCode")
let { value, isEditBox } = this.state
let { value, isEditBox, userDidModify } = this.state
return (
<div className="body-param">
@@ -104,14 +112,18 @@ export default class RequestBodyEditor extends PureComponent {
value={ value }/>)
}
<div className="body-param-options">
{
!isExecute ? null
: <div className="body-param-edit">
<Button className={isEditBox ? "btn cancel body-param__example-edit" : "btn edit body-param__example-edit"}
onClick={this.toggleIsEditBox}>{ isEditBox ? "Cancel" : "Edit"}
</Button>
</div>
}
<div className="body-param-edit">
{
!isExecute ? null
: <Button className={isEditBox ? "btn cancel body-param__example-edit" : "btn edit body-param__example-edit"}
onClick={this.toggleIsEditBox}>{ isEditBox ? "Cancel" : "Edit"}
</Button>
}
{ userDidModify &&
<Button className="btn ml3" onClick={() => { this.resetValueToSample(mediaType) }}>Reset</Button>
}
</div>
</div>
</div>
+2 -2
View File
@@ -350,7 +350,7 @@ export function extractFileNameFromContentDispositionHeader(value){
if (responseFilename !== null && responseFilename.length > 1) {
return responseFilename[1]
}
return null
return null
}
// PascalCase, aka UpperCamelCase
@@ -559,7 +559,7 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
} else if ( type === "array" ) {
let itemType
if ( !value.count() ) { return errors }
if ( !listCheck || !value.count() ) { return errors }
itemType = paramDetails.getIn(["items", "type"])
+4 -1
View File
@@ -45,7 +45,10 @@ export default class Topbar extends React.Component {
setSearch = (spec) => {
let search = parseSearch()
search["urls.primaryName"] = spec.name
window.location.search = serializeSearch(search)
const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}`
if(window && window.history && window.history.pushState) {
window.history.replaceState(null, "", `${newUrl}?${serializeSearch(search)}`)
}
}
setSelectedUrl = (selectedUrl) => {
+1
View File
@@ -21,6 +21,7 @@
.authorize
{
padding-right: 20px;
margin-right: 10px;
}
}
+1
View File
@@ -1,5 +1,6 @@
.swagger-ui
{
@import '~tachyons-sass/tachyons.scss';
@import 'mixins';
@import 'variables';
@import 'colors';
+24
View File
@@ -24,6 +24,18 @@ describe("Markdown component", function() {
const el = render(<Markdown source={str} />)
expect(el.html()).toEqual(`<div class="markdown"><p><img src="http://image.source" title="Image title"></p>\n</div>`)
})
it("allows image elements with https scheme", function() {
const str = `![Image alt text](https://image.source "Image title")`
const el = render(<Markdown source={str} />)
expect(el.html()).toEqual(`<div class="markdown"><p><img src="https://image.source" title="Image title"></p>\n</div>`)
})
it("allows image elements with data scheme", function() {
const str = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==">`
const el = render(<Markdown source={str} />)
expect(el.html()).toEqual(`<div class="markdown"><p>` + str + `</p>\n</div>`)
})
it("allows heading elements", function() {
const str = `
@@ -51,6 +63,18 @@ describe("Markdown component", function() {
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="http://image.source" title="Image title"></p></div></div>`)
})
it("allows image elements with https scheme", function() {
const str = `![Image alt text](https://image.source "Image title")`
const el = render(<OAS3Markdown source={str} />)
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div><p><img src="https://image.source" title="Image title"></p></div></div>`)
})
it("allows image elements with data scheme", function() {
const str = `<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==">`
const el = render(<OAS3Markdown source={str} />)
expect(el.html()).toEqual(`<div class="renderedMarkdown"><div>` + str + `</div></div>`)
})
it("allows heading elements", function() {
const str = `
# h1