Compare commits

...
71 Commits
Author SHA1 Message Date
kyle 7693dfe5bc Merge pull request #4036 from shockey/v/3.7.0
v3.7.0
2017-12-16 00:36:21 -08:00
Kyle Shockey 7faf79ae38 Fix deepLinking scroll behavior 2017-12-16 00:28:53 -08:00
Kyle Shockey 9b5accc17f v3.7.0 2017-12-16 00:10:01 -08:00
kyle d0ffb2bb9d Merge pull request #4010 from heldersepu/master
Add defaultModelsExpandDepth
2017-12-15 18:31:03 -08:00
Kyle Shockey 87572a856b Remove redundant changes to dist/index.html
This is not necessary, since all of these options are the same
as the defaults
2017-12-15 18:25:37 -08:00
Kyle Shockey 292639de57 Undo changes to dev-helpers/index.html 2017-12-15 18:24:43 -08:00
kyle 15dbc20efd Merge branch 'master' into master 2017-12-15 18:22:07 -08:00
kyle 5e72f68738 Merge pull request #4020 from heldersepu/patch-1
Update response-body.jsx to support SVG images
2017-12-15 17:29:44 -08:00
kyle 2b3a590e29 Merge branch 'master' into patch-1 2017-12-15 17:26:53 -08:00
kyle 0413410a1d Merge pull request #3244 from swagger-api/feature/small-tweaks
Some small tweaks
2017-12-15 17:26:31 -08:00
Kyle Shockey 49333dfadc Merge branch 'master' of github.com:swagger-api/swagger-ui into feature/small-tweaks 2017-12-15 17:22:03 -08:00
Kyle Shockey d65d7b3dd7 Revert /dist to contents of master 2017-12-15 17:21:49 -08:00
kyle e594392920 Merge pull request #3980 from thompsongl/ft/deeplinking-link-component
ft/deeplinking-link-component
2017-12-15 17:08:11 -08:00
kyle 48fd8f7689 Merge branch 'master' into ft/deeplinking-link-component 2017-12-15 17:05:22 -08:00
kyle bb54eaa127 Merge pull request #4019 from swagger-api/swagger-ui/master
Do not display undocumenetd when there is a default response
2017-12-14 15:43:25 -08:00
Greg Thompson a41cdfd650 Merge branch 'master' into ft/deeplinking-link-component 2017-12-13 08:32:57 -06:00
Gonen Dukas 4320118f17 Merge branch 'master' into master 2017-12-13 14:51:43 +02:00
kyle 7f19d791f8 Merge pull request #4026 from swagger-api/ft/docs
Clarify wrapComponent interface in Plugin API docs
2017-12-12 15:55:23 -08:00
kyle 9147d2eac2 Merge branch 'master' into ft/docs 2017-12-12 15:49:23 -08:00
kyle 1613455bc4 Merge pull request #4006 from MartinNowak/patch-1
fix example integration
2017-12-12 15:49:05 -08:00
Helder Sepulveda 6ba6039eb7 Merge branch 'master' into master 2017-12-12 17:48:40 -05:00
Helder Sepulveda f3cb0d7195 Merge branch 'master' into patch-1 2017-12-12 17:44:50 -05:00
kyle 9034e3fcdf Merge branch 'master' into patch-1 2017-12-12 14:35:06 -08:00
kyle a9ee23413d Merge branch 'master' into ft/docs 2017-12-12 14:34:27 -08:00
kyle 9a7ef85aa4 Clarify wrapComponent interface in Plugin API docs 2017-12-12 14:33:41 -08:00
kyle 1b5c060834 Merge pull request #4013 from heldersepu/bug/loading
Show loading message when we are loading
2017-12-12 13:38:32 -08:00
Kyle Shockey dfa96e66a4 Improve a handful of error surfacing messages
`Spec` => `API definition`, notably.
2017-12-12 13:34:25 -08:00
Kyle Shockey 00f4fb3326 Add margin to loading container 2017-12-12 13:25:36 -08:00
Kyle Shockey 3db4f6c93a Wrap BaseLayout loading messages in swagger-ui+loading-container 2017-12-12 13:24:42 -08:00
Kyle Shockey 0864ca849f Use throbber in Standalone layout; center loading messages and content 2017-12-12 13:07:18 -08:00
kyle faa9ada6b8 class => className 2017-12-12 12:31:55 -08:00
Greg Thompson 0e883d4a7a Merge remote-tracking branch 'upstream/master' into ft/deeplinking-link-component 2017-12-12 09:18:12 -06:00
Helder Sepulveda b2a435afdc Replace text with Loading throbber 2017-12-12 07:41:33 -05:00
kyle 5c17153df1 Merge branch 'master' into master 2017-12-11 20:29:02 -08:00
kyle a967be9438 Merge branch 'master' into patch-1 2017-12-11 19:21:26 -08:00
kyle aaf62a4e60 Merge branch 'master' into patch-1 2017-12-11 19:20:29 -08:00
kyle 91ed3baae7 Merge branch 'master' into bug/loading 2017-12-11 19:18:52 -08:00
kyle 2f32056fae Merge pull request #3812 from swagger-api/feature/deeplink-zenscroll
Add zenscroll instead of scroll-to
2017-12-11 19:18:20 -08:00
kyle af14cc9e78 Add missing comma 2017-12-11 19:09:00 -08:00
kyle a94c6c0e7f Merge branch 'master' into feature/deeplink-zenscroll 2017-12-11 19:05:16 -08:00
Greg Thompson f819612144 Merge branch 'master' into ft/deeplinking-link-component 2017-12-11 14:28:28 -06:00
Greg Thompson d2e931f3e1 DeepLink feedback 2017-12-11 14:27:28 -06:00
Helder Sepulveda 8becc9a9a7 Update response-body.jsx
Add support for svg images, with this change we will show an actual preview of the image
2017-12-11 15:14:58 -05:00
Gonen Dukas a5d1853557 Do not display undocumenetd when there is a default response 2017-12-11 17:49:16 +02:00
Helder Sepulveda fb8c3e46e7 Merge branch 'master' into master 2017-12-11 08:51:02 -05:00
Helder Sepulveda 58b64294c8 Merge branch 'master' into bug/loading 2017-12-11 08:50:34 -05:00
Helder Sepulveda d7857052c7 Merge branch 'master' into master 2017-12-09 11:23:43 -05:00
Helder Sepulveda 040d648e64 Merge branch 'master' into bug/loading 2017-12-09 11:22:49 -05:00
HelderSepu 67b2b716e4 Show loading message when we are loading 2017-12-09 11:12:41 -05:00
HelderSepu 28c706c70a Add defaultModelsExpandDepth
This change separates:
the Model (the one on the model-example section)
from
the Models (the ones at the bottom)
2017-12-08 21:12:41 -05:00
Greg Thompson 05fd5b354d update test 2017-12-08 10:20:55 -06:00
Greg Thompson f21601b0e8 Merge branch 'master' into ft/deeplinking-link-component 2017-12-08 09:54:58 -06:00
Martin Nowak 08b8f9c35a fix example integration 2017-12-08 13:22:25 +01:00
Greg Thompson 5bc8ba3694 Merge branch 'master' into ft/deeplinking-link-component 2017-12-04 14:15:36 -06:00
Greg Thompson 661b60fade add isShown prop 2017-12-04 14:14:28 -06:00
Josh Ponelat 780c5f1b83 Add conditionals to ModelWrapper testing for layout props 2017-12-04 16:11:02 +02:00
Josh Ponelat 41ae8242b6 fix test 2017-12-04 16:10:43 +02:00
Josh Ponelat c260263e4e fix issues with deeplink conflicts 2017-12-04 16:10:43 +02:00
Liam Shaw 80ec610485 add zen scroll 2017-12-04 16:10:43 +02:00
Josh Ponelat 3893cb4396 deep linking for models, operations and tags 2017-12-04 16:10:42 +02:00
Josh Ponelat f6b86d2d33 Refactor layout .show/.isShown to handle branch nodes 2017-12-04 16:09:24 +02:00
Greg Thompson 0b8cd7e32f add presentational component to allow for wrapping deeplinking links 2017-12-01 14:30:37 -06:00
Josh Ponelat 3681e86fad build 2017-10-25 09:49:07 +02:00
Josh Ponelat 5db6a1d0c9 add guards to specSelectors 2017-10-25 09:39:44 +02:00
Josh Ponelat 1c6f8e8327 refactor specSelectors.allowTryItOutFor 2017-10-25 09:39:44 +02:00
Josh Ponelat c6f354ae6c clean up spec actions a bit 2017-10-25 09:39:44 +02:00
Josh Ponelat e8772fbe2a fix typo in error message 2017-10-25 09:39:40 +02:00
Josh Ponelat 22732e8cc5 change : {} to fromJS({}) in param-body.jsx 2017-10-25 09:39:40 +02:00
Josh Ponelat a14b4c8039 Extend AST traversal to include string pointer 2017-10-25 09:39:40 +02:00
Josh Ponelat 84cc9489d4 fix typo with clear_validate_params 2017-10-25 09:39:31 +02:00
Josh Ponelat 2a4c8b9377 add .aignore 2017-10-25 09:39:31 +02:00
38 changed files with 293 additions and 158 deletions
+1
View File
@@ -0,0 +1 @@
dist/
+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.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.7.0 | 2017-12-15 | 2.0, 3.0 | [tag v3.7.0](https://github.com/swagger-api/swagger-ui/tree/v3.7.0)
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)
+15 -15
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
+1 -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
+30 -3
View File
@@ -293,7 +293,7 @@ const MyWrapSelectorsPlugin = function(system) {
Wrap Components allow you to override a component registered within the system.
Wrap Components are function factories with the signature `(OriginalComponent, system) => props => ReactElement`.
Wrap Components are function factories with the signature `(OriginalComponent, system) => props => ReactElement`. If you'd prefer to provide a React component class, `(OriginalComponent, system) => ReactClass` works as well.
```javascript
const MyWrapBuiltinComponentPlugin = function(system) {
@@ -310,9 +310,12 @@ const MyWrapBuiltinComponentPlugin = function(system) {
}
```
```javascript
// Overriding a component from a plugin
Here's another example that includes a code sample of a component that will be wrapped:
```javascript
///// Overriding a component from a plugin
// Here's our normal, unmodified component.
const MyNumberDisplayPlugin = function(system) {
return {
components: {
@@ -321,6 +324,7 @@ const MyNumberDisplayPlugin = function(system) {
}
}
// Here's a component wrapper defined as a function.
const MyWrapComponentPlugin = function(system) {
return {
wrapComponents: {
@@ -328,6 +332,7 @@ const MyWrapComponentPlugin = function(system) {
if(props.number > 10) {
return <div>
<h3>Warning! Big number ahead.</h3>
<OriginalComponent {...props} />
</div>
} else {
return <Original {...props} />
@@ -336,8 +341,30 @@ const MyWrapComponentPlugin = function(system) {
}
}
}
// Alternatively, here's the same component wrapper defined as a class.
const MyWrapComponentPlugin = function(system) {
return {
wrapComponents: {
NumberDisplay: (Original, system) => class WrappedNumberDisplay extends React.component {
render() {
if(props.number > 10) {
return <div>
<h3>Warning! Big number ahead.</h3>
<OriginalComponent {...props} />
</div>
} else {
return <Original {...props} />
}
}
}
}
}
}
```
##### fn
The fn interface allows you to add helper functions to the system for use elsewhere.
+3 -2
View File
@@ -49,8 +49,9 @@ Parameter Name | Description
--- | ---
`deepLinking` | `Boolean=false`. If set to `true`, enables deep linking for tags and operations. See the [Deep Linking documentation](/docs/usage/deep-linking.md) for more information.
`displayOperationId` | `Boolean=false`. Controls the display of operationId in operations list. The default is `false`.
`defaultModelExpandDepth` | `Number=1`. The default expansion depth for models.
`defaultModelRendering` | `String=["example"*, "model"]`. 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.)
`defaultModelsExpandDepth` | `Number=1`. The default expansion depth for models (set to -1 completely hide the models).
`defaultModelExpandDepth` | `Number=1`. The default expansion depth for the model on the model-example section.
`defaultModelRendering` | `String=["example"*, "model"]`. Controls how the model is 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.)
`displayRequestDuration` | `Boolean=false`. Controls the display of the request duration (in milliseconds) for Try-It-Out requests.
`docExpansion` | `String=["list"*, "full", "none"]`. Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing).
`filter` | `Boolean=false OR String`. If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be Boolean to enable or disable, or a string, in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag.
+2 -2
View File
@@ -49,7 +49,7 @@ const ui = SwaggerUIBundle({
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
]
],
layout: "StandaloneLayout"
})
```
@@ -86,7 +86,7 @@ This will serve Swagger UI at `/swagger` instead of `/`.
You can embed Swagger-UI's code directly in your HTML by using unkpg's interface:
```html
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js">
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<!-- `SwaggerUIBundle` is now available on the page -->
```
+4 -3
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.6.1",
"version": "3.7.0",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -81,13 +81,14 @@
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.4.1",
"swagger-client": "^3.4.2",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
"xml": "1.0.1",
"xml-but-prettier": "^1.0.1",
"yaml-js": "0.2.0"
"yaml-js": "0.2.0",
"zenscroll": "4.0.0"
},
"devDependencies": {
"autoprefixer": "7.1.1",
+1 -1
View File
@@ -39,7 +39,7 @@ export default class ArrayModel extends Component {
*/
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
+20
View File
@@ -0,0 +1,20 @@
import React from "react"
import PropTypes from "prop-types"
export const DeepLink = ({ enabled, path, text }) => {
return (
<a className="nostyle"
onClick={enabled ? (e) => e.preventDefault() : null}
href={enabled ? `#/${path}` : null}>
<span>{text}</span>
</a>
)
}
DeepLink.propTypes = {
enabled: PropTypes.bool,
isShown: PropTypes.bool,
path: PropTypes.string,
text: PropTypes.string
}
export default DeepLink
+12 -1
View File
@@ -61,7 +61,18 @@ export default class BaseLayout extends React.Component {
const isSpecEmpty = !specSelectors.specStr()
if(isSpecEmpty) {
return <h4>No spec provided.</h4>
let loadingMessage
if(isLoading) {
loadingMessage = <div className="loading"></div>
} else {
loadingMessage = <h4>No API definition provided.</h4>
}
return <div className="swagger-ui">
<div className="loading-container">
{loadingMessage}
</div>
</div>
}
return (
+25 -9
View File
@@ -4,31 +4,47 @@ import PropTypes from "prop-types"
export default class ModelCollapse extends Component {
static propTypes = {
collapsedContent: PropTypes.any,
collapsed: PropTypes.bool,
expanded: PropTypes.bool,
children: PropTypes.any,
title: PropTypes.element
title: PropTypes.element,
modelName: PropTypes.string,
onToggle: PropTypes.func.isRequired
}
static defaultProps = {
collapsedContent: "{...}",
collapsed: true,
expanded: false,
title: null
}
constructor(props, context) {
super(props, context)
let { collapsed, collapsedContent } = this.props
let { expanded, collapsedContent } = this.props
this.state = {
collapsed: collapsed !== undefined ? collapsed : ModelCollapse.defaultProps.collapsed,
expanded : expanded,
collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent
}
}
componentWillReceiveProps(nextProps){
if(this.props.expanded!= nextProps.expanded){
this.setState({expanded: nextProps.expanded})
}
}
toggleCollapsed=()=>{
if(this.props.onToggle){
this.props.onToggle(this.props.modelName,!this.state.expanded)
}
this.setState({
collapsed: !this.state.collapsed
expanded: !this.state.expanded
})
}
@@ -38,10 +54,10 @@ export default class ModelCollapse extends Component {
<span>
{ title && <span onClick={this.toggleCollapsed} style={{ "cursor": "pointer" }}>{title}</span> }
<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>
{ this.state.collapsed ? this.state.collapsedContent : this.props.children }
{ this.state.expanded ? this.props.children :this.state.collapsedContent }
</span>
)
}
}
}
+22 -3
View File
@@ -1,22 +1,41 @@
import React, { Component, } from "react"
import PropTypes from "prop-types"
//import layoutActions from "actions/layout"
export default class ModelWrapper extends Component {
export default class ModelComponent extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.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(){
let { getComponent, getConfigs } = this.props
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">
<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>
}
}
+12 -9
View File
@@ -13,14 +13,14 @@ export default class Models extends Component {
render(){
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
let definitions = specSelectors.definitions()
let { docExpansion, defaultModelExpandDepth } = getConfigs()
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
let { docExpansion, defaultModelsExpandDepth } = getConfigs()
if (!definitions.size || defaultModelsExpandDepth < 0) return null
let showModels = layoutSelectors.isShown("models", defaultModelsExpandDepth > 0 && docExpansion !== "none")
const specPathBase = specSelectors.isOAS3() ? ["components", "schemas"] : ["definitions"]
const ModelWrapper = getComponent("ModelWrapper")
const Collapse = getComponent("Collapse")
if (!definitions.size) return null
const Collapse = getComponent("Collapse")
return <section className={ showModels ? "models is-open" : "models"}>
<h4 onClick={() => layoutActions.show("models", !showModels)}>
@@ -32,14 +32,17 @@ export default class Models extends Component {
<Collapse isOpened={showModels}>
{
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 }
expandDepth={ defaultModelExpandDepth }
expandDepth={ defaultModelsExpandDepth }
schema={ model }
specPath={[...specPathBase, name]}
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }/>
specSelectors={ specSelectors }
getConfigs = {getConfigs}
layoutSelectors = {layoutSelectors}
layoutActions = {layoutActions}/>
</div>
}).toArray()
}
+11 -4
View File
@@ -10,6 +10,8 @@ export default class ObjectModel extends Component {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
expanded: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
@@ -19,9 +21,8 @@ export default class ObjectModel extends Component {
}
render(){
let { schema, name, isRef, getComponent, getConfigs, depth, specPath, expandDepth, ...otherProps } = this.props
let { specSelectors } = otherProps
let { schema, name, isRef, getComponent, getConfigs, depth, onToggle, expanded, specPath, ...otherProps } = this.props
let { specSelectors,expandDepth } = otherProps
const { isOAS3 } = specSelectors
if(!schema) {
@@ -61,7 +62,13 @@ export default class ObjectModel extends Component {
</span>
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>
{
!isRef ? null : <JumpToPathSection />
+7 -7
View File
@@ -102,12 +102,13 @@ export default class Operation extends PureComponent {
const Schemes = getComponent( "schemes" )
const OperationServers = getComponent( "OperationServers" )
const OperationExt = getComponent( "OperationExt" )
const DeepLink = getComponent( "DeepLink" )
const { showExtensions } = getConfigs()
// Merge in Live Response
if(responses && response && response.size > 0) {
let notDocumented = !responses.get(String(response.get("status")))
let notDocumented = !responses.get(String(response.get("status"))) && !responses.get("default")
response = response.set("notDocumented", notDocumented)
}
@@ -120,12 +121,11 @@ export default class Operation extends PureComponent {
and pulled in with getComponent */}
<span className="opblock-summary-method">{method.toUpperCase()}</span>
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
<a
className="nostyle"
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null}
href={isDeepLinkingEnabled ? `#/${isShownKey.join("/")}` : null}>
<span>{path}</span>
</a>
<DeepLink
enabled={isDeepLinkingEnabled}
isShown={isShown}
path={`${isShownKey.join("/")}`}
text={path} />
<JumpToPath path={specPath} /> {/*TODO: use wrapComponents here, swagger-ui doesn't care about jumpToPath */}
</span>
+6 -6
View File
@@ -37,6 +37,7 @@ export default class Operations extends React.Component {
const OperationContainer = getComponent("OperationContainer", true)
const Collapse = getComponent("Collapse")
const Markdown = getComponent("Markdown")
const DeepLink = getComponent("DeepLink")
let {
docExpansion,
@@ -79,12 +80,11 @@ export default class Operations extends React.Component {
onClick={() => layoutActions.show(isShownKey, !showTag)}
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
id={isShownKey.join("-")}>
<a
className="nostyle"
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null}
href= {isDeepLinkingEnabled ? `#/${tag}` : null}>
<span>{tag}</span>
</a>
<DeepLink
enabled={isDeepLinkingEnabled}
isShown={showTag}
path={tag}
text={tag} />
{ !tagDescription ? null :
<small>
<Markdown source={tagDescription} />
+1 -1
View File
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : {}
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : fromJS({})
let isXml = /xml/i.test(consumesValue)
let isJson = /json/i.test(consumesValue)
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
+5 -1
View File
@@ -43,7 +43,11 @@ export default class ResponseBody extends React.Component {
// Image
} else if (/^image\//i.test(contentType)) {
bodyEl = <img style={{ maxWidth: "100%" }} src={ window.URL.createObjectURL(content) } />
if(contentType.includes("svg")) {
bodyEl = <div> { content } </div>
} else {
bodyEl = <img style={{ maxWidth: "100%" }} src={ window.URL.createObjectURL(content) } />
}
// Audio
} else if (/^audio\//i.test(contentType)) {
+1
View File
@@ -47,6 +47,7 @@ module.exports = function SwaggerUI(opts) {
showMutatedRequest: true,
defaultModelRendering: "example",
defaultModelExpandDepth: 1,
defaultModelsExpandDepth: 1,
showExtensions: false,
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
+1 -1
View File
@@ -46,7 +46,7 @@ export default function authorize ( { auth, authActions, errActions, configs, au
authId: name,
source: "validation",
level: "error",
message: "oauth2RedirectUri configuration is not passed. Oauth2 authorization cannot be performed."
message: "oauth2RedirectUrl configuration is not passed. Oauth2 authorization cannot be performed."
})
return
}
+33 -15
View File
@@ -103,30 +103,30 @@ export function positionRangeForPath(yaml, path) {
let ast = cachedCompose(yaml)
// simply walks the tree using current path recursively to the point that
// simply walks the tree using astValue path recursively to the point that
// path is empty.
return find(ast)
function find(current) {
if (current.tag === MAP_TAG) {
for (i = 0; i < current.value.length; i++) {
var pair = current.value[i]
function find(astValue, astKeyValue) {
if (astValue.tag === MAP_TAG) {
for (i = 0; i < astValue.value.length; i++) {
var pair = astValue.value[i]
var key = pair[0]
var value = pair[1]
if (key.value === path[0]) {
path.shift()
return find(value)
return find(value, key)
}
}
}
if (current.tag === SEQ_TAG) {
var item = current.value[path[0]]
if (astValue.tag === SEQ_TAG) {
var item = astValue.value[path[0]]
if (item && item.tag) {
path.shift()
return find(item)
return find(item, astKeyValue)
}
}
@@ -135,17 +135,35 @@ export function positionRangeForPath(yaml, path) {
return invalidRange
}
return {
/* jshint camelcase: false */
const range = {
start: {
line: current.start_mark.line,
column: current.start_mark.column
line: astValue.start_mark.line,
column: astValue.start_mark.column,
pointer: astValue.start_mark.pointer,
},
end: {
line: current.end_mark.line,
column: current.end_mark.column
line: astValue.end_mark.line,
column: astValue.end_mark.column,
pointer: astValue.end_mark.pointer,
}
}
if(astKeyValue) {
// eslint-disable-next-line camelcase
range.key_start = {
line: astKeyValue.start_mark.line,
column: astKeyValue.start_mark.column,
pointer: astKeyValue.start_mark.pointer,
}
// eslint-disable-next-line camelcase
range.key_end = {
line: astKeyValue.end_mark.line,
column: astKeyValue.end_mark.column,
pointer: astKeyValue.end_mark.pointer,
}
}
return range
}
}
@@ -1,8 +1,7 @@
import scrollTo from "scroll-to-element"
import zenscroll from "zenscroll"
import { escapeDeepLinkPath } from "core/utils"
const SCROLL_OFFSET = -5
let hasHashBeenParsed = false
let hasHashBeenParsed = false //TODO this forces code to only run once which may prevent scrolling if page not refreshed
export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => {
@@ -12,7 +11,6 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
return
}
if(window.location.hash && !hasHashBeenParsed ) {
let hash = window.location.hash.slice(1) // # is first character
@@ -30,21 +28,35 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
let [tag, operationId] = hash.split("/")
let swaggerUI = document.querySelector(".swagger-ui")
let myScroller = zenscroll.createScroller(swaggerUI)
let target
if(tag && operationId) {
// Pre-expand and scroll to the operation
layoutActions.show(["operations-tag", tag], true)
layoutActions.show(["operations", tag, operationId], true)
scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, {
offset: SCROLL_OFFSET
})
target = document
.getElementById(`operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`)
} else if(tag) {
// Pre-expand and scroll to the tag
layoutActions.show(["operations-tag", tag], true)
scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, {
offset: SCROLL_OFFSET
})
target = document.getElementById(`operations-tag-${escapeDeepLinkPath(tag)}`)
}
if(target) {
myScroller.to(target)
setTimeout(() => {
// Backup functionality: if we're still at the top of the document,
// scroll on the entire page (not within the Swagger-UI container)
if(zenscroll.getY() === 0) {
zenscroll.to(target)
}
}, 50)
}
}
-14
View File
@@ -37,17 +37,3 @@ export function changeMode(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}
// }
// }
+9 -4
View File
@@ -1,3 +1,4 @@
import { fromJS } from "immutable"
import {
UPDATE_LAYOUT,
UPDATE_FILTER,
@@ -12,9 +13,14 @@ export default {
[UPDATE_FILTER]: (state, action) => state.set("filter", action.payload),
[SHOW]: (state, action) => {
let thing = action.payload.thing
let shown = action.payload.shown
return state.setIn(["shown"].concat(thing), shown)
const isShown = action.payload.shown
// This is one way to serialize an array, another (preferred) is to convert to json-pointer
// 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) => {
@@ -24,4 +30,3 @@ export default {
}
}
+2 -2
View File
@@ -1,5 +1,6 @@
import { createSelector } from "reselect"
import { normalizeArray } from "core/utils"
import { fromJS } from "immutable"
const state = state => state
@@ -9,7 +10,7 @@ export const currentFilter = state => state.get("filter")
export const isShown = (state, thing, def) => {
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="") => {
@@ -21,4 +22,3 @@ export const showSummary = createSelector(
state,
state => !isShown(state, "editor")
)
+9 -26
View File
@@ -1,6 +1,7 @@
import YAML from "js-yaml"
import parseUrl from "url-parse"
import serializeError from "serialize-error"
import isString from "lodash/isString"
import { isJSONObject } from "core/utils"
// Actions conform to FSA (flux-standard-actions)
@@ -22,22 +23,16 @@ export const UPDATE_OPERATION_VALUE = "spec_update_operation_value"
export const UPDATE_RESOLVED = "spec_update_resolved"
export const SET_SCHEME = "set_scheme"
export function updateSpec(spec) {
if(spec instanceof Error) {
return {type: UPDATE_SPEC, error: true, payload: spec}
}
const toStr = (str) => isString(str) ? str : ""
export function updateSpec(spec) {
const cleanSpec = (toStr(spec)).replace(/\t/g, " ")
if(typeof spec === "string") {
return {
type: UPDATE_SPEC,
payload: spec.replace(/\t/g, " ") || ""
payload: cleanSpec
}
}
return {
type: UPDATE_SPEC,
payload: ""
}
}
export function updateResolved(spec) {
@@ -52,9 +47,6 @@ export function updateUrl(url) {
}
export function updateJsonSpec(json) {
if(!json || typeof json !== "object") {
throw new Error("updateJson must only accept a simple JSON object")
}
return {type: UPDATE_JSON, payload: json}
}
@@ -76,7 +68,10 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
line: e.mark && e.mark.line ? e.mark.line + 1 : undefined
})
}
return specActions.updateJsonSpec(json)
if(json) {
return specActions.updateJsonSpec(json)
}
return {}
}
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => {
@@ -130,18 +125,6 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
})
}
export const formatIntoYaml = () => ({specActions, specSelectors}) => {
let { specStr } = specSelectors
let { updateSpec } = specActions
try {
let yaml = YAML.safeDump(YAML.safeLoad(specStr()), {indent: 2})
updateSpec(yaml)
} catch(e) {
updateSpec(e)
}
}
export function changeParam( path, paramName, paramIn, value, isXml ){
return {
type: UPDATE_PARAM,
+7 -2
View File
@@ -256,10 +256,11 @@ export const allowTryItOutFor = () => {
// Get the parameter value by parameter name
export function getParameter(state, pathMethod, name, inType) {
pathMethod = pathMethod || []
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
return params.filter( (p) => {
return params.find( (p) => {
return Map.isMap(p) && p.get("name") === name && p.get("in") === inType
}).first()
}) || Map() // Always return a map
}
export const hasHost = createSelector(
@@ -272,6 +273,7 @@ export const hasHost = createSelector(
// Get the parameter values, that the user filled out
export function parameterValues(state, pathMethod, isXml) {
pathMethod = pathMethod || []
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
return params.reduce( (hash, p) => {
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
@@ -295,6 +297,7 @@ export function parametersIncludeType(parameters, typeValue="") {
// Get the consumes/produces value that the user selected
export function contentTypeValues(state, pathMethod) {
pathMethod = pathMethod || []
let op = spec(state).getIn(["paths", ...pathMethod], fromJS({}))
const parameters = op.get("parameters") || new List()
@@ -313,6 +316,7 @@ export function contentTypeValues(state, pathMethod) {
// Get the consumes/produces by path
export function operationConsumes(state, pathMethod) {
pathMethod = pathMethod || []
return spec(state).getIn(["paths", ...pathMethod, "consumes"], fromJS({}))
}
@@ -329,6 +333,7 @@ export const canExecuteScheme = ( state, path, method ) => {
}
export const validateBeforeExecute = ( state, pathMethod ) => {
pathMethod = pathMethod || []
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
let isValid = true
+3 -1
View File
@@ -61,6 +61,7 @@ import PrimitiveModel from "core/components/primitive-model"
import Property from "core/components/property"
import TryItOutButton from "core/components/try-it-out-button"
import VersionStamp from "core/components/version-stamp"
import DeepLink from "core/components/deep-link"
import Markdown from "core/components/providers/markdown"
@@ -121,7 +122,8 @@ export default function() {
OperationExt,
OperationExtRow,
ParameterExt,
OperationContainer
OperationContainer,
DeepLink
}
}
+9 -3
View File
@@ -1,3 +1,5 @@
import React from "react"
import PropTypes from "prop-types"
@@ -32,17 +34,21 @@ export default class StandaloneLayout extends React.Component {
{ Topbar ? <Topbar /> : null }
{ loadingStatus === "loading" &&
<div className="info">
<h4 className="title">Loading...</h4>
<div className="loading-container">
<div className="loading"></div>
</div>
</div>
}
{ loadingStatus === "failed" &&
<div className="info">
<h4 className="title">Failed to load spec.</h4>
<div className="loading-container">
<h4 className="title">Failed to load API definition.</h4>
</div>
</div>
}
{ loadingStatus === "failedConfig" &&
<div className="info" style={{ maxWidth: "880px", marginLeft: "auto", marginRight: "auto", textAlign: "center" }}>
<h4 className="title">Failed to load config.</h4>
<h4 className="title">Failed to load remote configuration.</h4>
</div>
}
{ !loadingStatus || loadingStatus === "success" && <BaseLayout /> }
+5
View File
@@ -653,6 +653,11 @@
.loading-container
{
padding: 40px 0 60px;
margin-top: 1em;
min-height: 1px;
display: flex;
justify-content: center;
.loading
{
position: relative;
+3 -3
View File
@@ -32,18 +32,18 @@ describe("<Models/>", function(){
layoutActions: {},
getConfigs: () => ({
docExpansion: "list",
defaultModelExpandDepth: 0
defaultModelsExpandDepth: 0
})
}
it("passes defaultModelExpandDepth to ModelWrapper", function(){
it("passes defaultModelsExpandDepth 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)
expect(wrapper.find("ModelWrapper").length).toBeGreaterThan(0)
wrapper.find("ModelComponent").forEach((modelWrapper) => {
expect(modelWrapper.props().expandDepth).toBe(0)
})
+2
View File
@@ -3,11 +3,13 @@ import React from "react"
import expect, { createSpy } from "expect"
import { render } from "enzyme"
import { fromJS } from "immutable"
import DeepLink from "components/deep-link"
import Operations from "components/operations"
import {Collapse} from "components/layout-utils"
const components = {
Collapse,
DeepLink,
OperationContainer: ({ path, method }) => <span className="mocked-op" id={`${path}-${method}`} />
}