deep linking for models, operations and tags
This commit is contained in:
@@ -38,7 +38,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
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
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) => {
|
||||||
|
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")
|
||||||
|
const 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>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,16 @@ 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 }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
getConfigs={ getConfigs }
|
specSelectors={ specSelectors }
|
||||||
specSelectors={ specSelectors }/>
|
getConfigs = {getConfigs}
|
||||||
|
layoutSelectors = {layoutSelectors}
|
||||||
|
layoutActions = {layoutActions}/>
|
||||||
</div>
|
</div>
|
||||||
}).toArray()
|
}).toArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -18,8 +20,8 @@ export default class ObjectModel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
let { schema, name, isRef, getComponent, getConfigs, depth, expandDepth, ...otherProps } = this.props
|
let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, ...otherProps } = this.props
|
||||||
let { specSelectors } = otherProps
|
let { specSelectors,expandDepth } = otherProps
|
||||||
let { isOAS3 } = specSelectors
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
if(!schema) {
|
if(!schema) {
|
||||||
@@ -60,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 name={ name }/>
|
!isRef ? null : <JumpToPathSection name={ name }/>
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user