Merge branch 'master' into patch-1

This commit is contained in:
kyle
2017-12-11 19:21:26 -08:00
committed by GitHub
23 changed files with 126 additions and 84 deletions

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 Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | ----- ------------------ | ------------ | -------------------------- | -----
3.6.0 | 2017-12-01 | 2.0, 3.0 | [tag v3.5=6.0](https://github.com/swagger-api/swagger-ui/tree/v3.6.0) 3.6.1 | 2017-12-01 | 2.0, 3.0 | [tag v3.6.1](https://github.com/swagger-api/swagger-ui/tree/v3.6.1)
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)

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

File diff suppressed because one or more lines are too long

2
dist/swagger-ui.css vendored

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

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.6.0", "version": "3.6.1",
"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": [
@@ -81,13 +81,14 @@
"scroll-to-element": "^2.0.0", "scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0", "serialize-error": "2.0.0",
"shallowequal": "0.2.2", "shallowequal": "0.2.2",
"swagger-client": "^3.4.0", "swagger-client": "^3.4.1",
"url-parse": "^1.1.8", "url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1", "whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1", "worker-loader": "^0.7.1",
"xml": "1.0.1", "xml": "1.0.1",
"xml-but-prettier": "^1.0.1", "xml-but-prettier": "^1.0.1",
"yaml-js": "0.2.0" "yaml-js": "0.2.0",
"zenscroll": "4.0.0"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "7.1.1", "autoprefixer": "7.1.1",

View File

@@ -39,7 +39,7 @@ export default class ArrayModel extends Component {
*/ */
return <span className="model"> return <span className="model">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]"> <ModelCollapse title={titleEl} expanded={ depth <= expandDepth } collapsedContent="[...]">
[ [
{ {
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null

View File

@@ -73,7 +73,7 @@ const ThrownErrorItem = ( { error, jumpToLine } ) => {
<span style={{ whiteSpace: "pre-line", "maxWidth": "100%" }}> <span style={{ whiteSpace: "pre-line", "maxWidth": "100%" }}>
{ error.get("message") } { error.get("message") }
</span> </span>
<div> <div style={{ "text-decoration": "underline", "cursor": "pointer" }}>
{ errorLine && jumpToLine ? <a onClick={jumpToLine.bind(null, errorLine)}>Jump to line { errorLine }</a> : null } { errorLine && jumpToLine ? <a onClick={jumpToLine.bind(null, errorLine)}>Jump to line { errorLine }</a> : null }
</div> </div>
</div> </div>

View File

@@ -4,31 +4,47 @@ import PropTypes from "prop-types"
export default class ModelCollapse extends Component { export default class ModelCollapse extends Component {
static propTypes = { static propTypes = {
collapsedContent: PropTypes.any, collapsedContent: PropTypes.any,
collapsed: PropTypes.bool, expanded: PropTypes.bool,
children: PropTypes.any, children: PropTypes.any,
title: PropTypes.element title: PropTypes.element,
modelName: PropTypes.string,
onToggle: PropTypes.func.isRequired
} }
static defaultProps = { static defaultProps = {
collapsedContent: "{...}", collapsedContent: "{...}",
collapsed: true, expanded: false,
title: null title: null
} }
constructor(props, context) { constructor(props, context) {
super(props, context) super(props, context)
let { collapsed, collapsedContent } = this.props let { expanded, collapsedContent } = this.props
this.state = { this.state = {
collapsed: collapsed !== undefined ? collapsed : ModelCollapse.defaultProps.collapsed, expanded : expanded,
collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent
} }
} }
componentWillReceiveProps(nextProps){
if(this.props.expanded!= nextProps.expanded){
this.setState({expanded: nextProps.expanded})
}
}
toggleCollapsed=()=>{ toggleCollapsed=()=>{
if(this.props.onToggle){
this.props.onToggle(this.props.modelName,!this.state.expanded)
}
this.setState({ this.setState({
collapsed: !this.state.collapsed expanded: !this.state.expanded
}) })
} }
@@ -38,9 +54,9 @@ export default class ModelCollapse extends Component {
<span> <span>
{ title && <span onClick={this.toggleCollapsed} style={{ "cursor": "pointer" }}>{title}</span> } { title && <span onClick={this.toggleCollapsed} style={{ "cursor": "pointer" }}>{title}</span> }
<span onClick={ this.toggleCollapsed } style={{ "cursor": "pointer" }}> <span onClick={ this.toggleCollapsed } style={{ "cursor": "pointer" }}>
<span className={ "model-toggle" + ( this.state.collapsed ? " collapsed" : "" ) }></span> <span className={ "model-toggle" + ( this.state.expanded ? "" : " collapsed" ) }></span>
</span> </span>
{ this.state.collapsed ? this.state.collapsedContent : this.props.children } { this.state.expanded ? this.props.children :this.state.collapsedContent }
</span> </span>
) )
} }

View File

@@ -1,22 +1,41 @@
import React, { Component, } from "react" import React, { Component, } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
//import layoutActions from "actions/layout"
export default class ModelWrapper extends Component {
export default class ModelComponent extends Component {
static propTypes = { static propTypes = {
schema: PropTypes.object.isRequired, schema: PropTypes.object.isRequired,
name: PropTypes.string, name: PropTypes.string,
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired, getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
expandDepth: PropTypes.number expandDepth: PropTypes.number,
layoutActions: PropTypes.object,
layoutSelectors: PropTypes.object.isRequired
}
onToggle = (name,isShown) => {
// If this prop is present, we'll have deepLinking for it
if(this.props.layoutActions) {
this.props.layoutActions.show(["models", name],isShown)
}
} }
render(){ render(){
let { getComponent, getConfigs } = this.props let { getComponent, getConfigs } = this.props
const Model = getComponent("Model") const Model = getComponent("Model")
let expanded
if(this.props.layoutSelectors) {
// If this is prop is present, we'll have deepLinking for it
expanded = this.props.layoutSelectors.isShown(["models",this.props.name])
}
return <div className="model-box"> return <div className="model-box">
<Model { ...this.props } getConfigs={ getConfigs } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/> <Model { ...this.props } getConfigs={ getConfigs } expanded={expanded} depth={ 1 } onToggle={ this.onToggle } expandDepth={ this.props.expandDepth || 0 }/>
</div> </div>
} }
} }

View File

@@ -32,14 +32,17 @@ export default class Models extends Component {
<Collapse isOpened={showModels}> <Collapse isOpened={showModels}>
{ {
definitions.entrySeq().map( ( [ name, model ])=>{ definitions.entrySeq().map( ( [ name, model ])=>{
return <div className="model-container" key={ `models-section-${name}` }>
return <div id={ `model-${name}` } className="model-container" key={ `models-section-${name}` }>
<ModelWrapper name={ name } <ModelWrapper name={ name }
expandDepth={ defaultModelExpandDepth } expandDepth={ defaultModelExpandDepth }
schema={ model } schema={ model }
specPath={[...specPathBase, name]} specPath={[...specPathBase, name]}
getComponent={ getComponent } getComponent={ getComponent }
getConfigs={ getConfigs } specSelectors={ specSelectors }
specSelectors={ specSelectors }/> getConfigs = {getConfigs}
layoutSelectors = {layoutSelectors}
layoutActions = {layoutActions}/>
</div> </div>
}).toArray() }).toArray()
} }

View File

@@ -10,6 +10,8 @@ export default class ObjectModel extends Component {
schema: PropTypes.object.isRequired, schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired, getConfigs: PropTypes.func.isRequired,
expanded: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
name: PropTypes.string, name: PropTypes.string,
isRef: PropTypes.bool, isRef: PropTypes.bool,
@@ -19,9 +21,8 @@ export default class ObjectModel extends Component {
} }
render(){ render(){
let { schema, name, isRef, getComponent, getConfigs, depth, specPath, expandDepth, ...otherProps } = this.props let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props
let { specSelectors } = otherProps let { specSelectors,expandDepth } = otherProps
const { isOAS3 } = specSelectors const { isOAS3 } = specSelectors
if(!schema) { if(!schema) {
@@ -61,7 +62,13 @@ export default class ObjectModel extends Component {
</span> </span>
return <span className="model"> return <span className="model">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent={ collapsedContent }> <ModelCollapse
modelName={name}
title={titleEl}
onToggle = {onToggle}
expanded={ expanded ? true : depth <= expandDepth }
collapsedContent={ collapsedContent }>
<span className="brace-open object">{ braceOpen }</span> <span className="brace-open object">{ braceOpen }</span>
{ {
!isRef ? null : <JumpToPathSection /> !isRef ? null : <JumpToPathSection />

View File

@@ -32,7 +32,8 @@ export default class Operation extends PureComponent {
static defaultProps = { static defaultProps = {
operation: null, operation: null,
response: null, response: null,
request: null request: null,
specPath: []
} }
render() { render() {
@@ -113,10 +114,10 @@ export default class Operation extends PureComponent {
let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method ) let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )
return ( return (
<div className={`opblock-summary opblock-summary-${method}`} onClick={toggleShown} >
{/*TODO: convert this into a component, that can be wrapped
and pulled in with getComponent */}
<div className={deprecated ? "opblock opblock-deprecated" : isShown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey.join("-")} > <div className={deprecated ? "opblock opblock-deprecated" : isShown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey.join("-")} >
<div className={`opblock-summary opblock-summary-${method}`} onClick={toggleShown} >
{/*TODO: convert this into a component, that can be wrapped
and pulled in with getComponent */}
<span className="opblock-summary-method">{method.toUpperCase()}</span> <span className="opblock-summary-method">{method.toUpperCase()}</span>
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } > <span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
<a <a

View File

@@ -31,6 +31,7 @@ export default class OperationContainer extends PureComponent {
request: PropTypes.instanceOf(Iterable), request: PropTypes.instanceOf(Iterable),
security: PropTypes.instanceOf(Iterable), security: PropTypes.instanceOf(Iterable),
isDeepLinkingEnabled: PropTypes.bool.isRequired, isDeepLinkingEnabled: PropTypes.bool.isRequired,
specPath: PropTypes.array.isRequired,
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
authActions: PropTypes.object, authActions: PropTypes.object,
@@ -141,6 +142,7 @@ export default class OperationContainer extends PureComponent {
displayOperationId, displayOperationId,
displayRequestDuration, displayRequestDuration,
isDeepLinkingEnabled, isDeepLinkingEnabled,
specPath,
specSelectors, specSelectors,
specActions, specActions,
getComponent, getComponent,
@@ -187,6 +189,7 @@ export default class OperationContainer extends PureComponent {
onTryoutClick={this.onTryoutClick} onTryoutClick={this.onTryoutClick}
onCancelClick={this.onCancelClick} onCancelClick={this.onCancelClick}
onExecute={this.onExecute} onExecute={this.onExecute}
specPath={specPath}
specActions={ specActions } specActions={ specActions }
specSelectors={ specSelectors } specSelectors={ specSelectors }

View File

@@ -1,8 +1,7 @@
import scrollTo from "scroll-to-element" import zenscroll from "zenscroll"
import { escapeDeepLinkPath } from "core/utils" import { escapeDeepLinkPath } from "core/utils"
const SCROLL_OFFSET = -5 let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed
let hasHashBeenParsed = false
export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => { export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => {
@@ -12,7 +11,6 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") { if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
return return
} }
if(window.location.hash && !hasHashBeenParsed ) { if(window.location.hash && !hasHashBeenParsed ) {
let hash = window.location.hash.slice(1) // # is first character let hash = window.location.hash.slice(1) // # is first character
@@ -30,21 +28,23 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
let [tag, operationId] = hash.split("/") let [tag, operationId] = hash.split("/")
let swaggerUI = document.querySelector(".swagger-ui")
let myScroller = zenscroll.createScroller(swaggerUI)
if(tag && operationId) { if(tag && operationId) {
// Pre-expand and scroll to the operation // Pre-expand and scroll to the operation
layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations-tag", tag], true)
layoutActions.show(["operations", tag, operationId], true) layoutActions.show(["operations", tag, operationId], true)
scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, { let target = document.getElementById(`operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`)
offset: SCROLL_OFFSET myScroller.to(target)
})
} else if(tag) { } else if(tag) {
// Pre-expand and scroll to the tag // Pre-expand and scroll to the tag
layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations-tag", tag], true)
scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, { let target = document.getElementById(`operations-tag-${escapeDeepLinkPath(tag)}`)
offset: SCROLL_OFFSET myScroller.to(target)
})
} }
} }

View File

@@ -37,17 +37,3 @@ export function changeMode(thing, mode="") {
payload: {thing, mode} payload: {thing, mode}
} }
} }
// export function onlyShow(thing, shown=true) {
// thing = normalizeArray(thing)
// if(thing.length < 2)
// throw new Error("layoutActions.onlyShow only works, when `thing` is an array with length > 1")
// return {
// type: ONLY_SHOW,
// payload: {thing, shown}
// }
// }

View File

@@ -1,3 +1,4 @@
import { fromJS } from "immutable"
import { import {
UPDATE_LAYOUT, UPDATE_LAYOUT,
UPDATE_FILTER, UPDATE_FILTER,
@@ -12,9 +13,14 @@ export default {
[UPDATE_FILTER]: (state, action) => state.set("filter", action.payload), [UPDATE_FILTER]: (state, action) => state.set("filter", action.payload),
[SHOW]: (state, action) => { [SHOW]: (state, action) => {
let thing = action.payload.thing const isShown = action.payload.shown
let shown = action.payload.shown // This is one way to serialize an array, another (preferred) is to convert to json-pointer
return state.setIn(["shown"].concat(thing), shown) // TODO: use json-pointer serilization instead of fromJS(...), for performance
const thingToShow = fromJS(action.payload.thing)
// This is a map of paths to bools
// eg: [one, two] => true
// eg: [one] => false
return state.update("shown", fromJS({}), a => a.set(thingToShow, isShown))
}, },
[UPDATE_MODE]: (state, action) => { [UPDATE_MODE]: (state, action) => {
@@ -24,4 +30,3 @@ export default {
} }
} }

View File

@@ -1,5 +1,6 @@
import { createSelector } from "reselect" import { createSelector } from "reselect"
import { normalizeArray } from "core/utils" import { normalizeArray } from "core/utils"
import { fromJS } from "immutable"
const state = state => state const state = state => state
@@ -9,7 +10,7 @@ export const currentFilter = state => state.get("filter")
export const isShown = (state, thing, def) => { export const isShown = (state, thing, def) => {
thing = normalizeArray(thing) thing = normalizeArray(thing)
return Boolean(state.getIn(["shown", ...thing], def)) return state.get("shown", fromJS({})).get(fromJS(thing), def)
} }
export const whatMode = (state, thing, def="") => { export const whatMode = (state, thing, def="") => {
@@ -21,4 +22,3 @@ export const showSummary = createSelector(
state, state,
state => !isShown(state, "editor") state => !isShown(state, "editor")
) )

View File

@@ -11,6 +11,7 @@
select select
{ {
min-width: 130px; min-width: 130px;
max-width: 100%;
} }
} }

View File

@@ -43,7 +43,7 @@ describe("<Models/>", function(){
// Then should render tabs // Then should render tabs
expect(wrapper.find("ModelCollapse").length).toEqual(1) expect(wrapper.find("ModelCollapse").length).toEqual(1)
expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0) expect(wrapper.find("ModelWrapper").length).toBeGreaterThan(0)
wrapper.find("ModelComponent").forEach((modelWrapper) => { wrapper.find("ModelComponent").forEach((modelWrapper) => {
expect(modelWrapper.props().expandDepth).toBe(0) expect(modelWrapper.props().expandDepth).toBe(0)
}) })