Merge branch 'master' into feature/spec-path

This commit is contained in:
kyle
2017-12-07 16:49:34 -08:00
committed by GitHub
105 changed files with 3313 additions and 746 deletions

View File

@@ -7,6 +7,7 @@ export default class ArrayModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
required: PropTypes.bool,
@@ -16,7 +17,7 @@ export default class ArrayModel extends Component {
}
render(){
let { getComponent, schema, depth, expandDepth, name, specPath } = this.props
let { getComponent, getConfigs, schema, depth, expandDepth, name, specPath } = this.props
let description = schema.get("description")
let items = schema.get("items")
let title = schema.get("title") || name
@@ -47,7 +48,7 @@ export default class ArrayModel extends Component {
!description ? null :
<Markdown source={ description } />
}
<span><Model { ...this.props } specPath={[...specPath, "items"]} name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
<span><Model { ...this.props } getConfigs={ getConfigs } specPath={[...specPath, "items"]} name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
]
</ModelCollapse>
</span>

View File

@@ -60,6 +60,9 @@ export default class ApiKeyAuth extends React.Component {
<Row>
<Markdown source={ schema.get("description") } />
</Row>
<Row>
<p>Name: <code>{ schema.get("name") }</code></p>
</Row>
<Row>
<p>In: <code>{ schema.get("in") }</code></p>
</Row>

View File

@@ -1,25 +1,23 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
export default class AuthorizeOperationBtn extends React.Component {
static propTypes = {
isAuthorized: PropTypes.bool.isRequired,
onClick: PropTypes.func
}
onClick =(e) => {
e.stopPropagation()
let { onClick } = this.props
let { security, authActions, authSelectors } = this.props
let definitions = authSelectors.getDefinitionsByNames(security)
authActions.showDefinitions(definitions)
if(onClick) {
onClick()
}
}
render() {
let { security, authSelectors } = this.props
let isAuthorized = authSelectors.isAuthorized(security)
if(isAuthorized === null) {
return null
}
let { isAuthorized } = this.props
return (
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
@@ -30,10 +28,4 @@ export default class AuthorizeOperationBtn extends React.Component {
)
}
static propTypes = {
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
security: ImPropTypes.iterable.isRequired
}
}

View File

@@ -41,6 +41,13 @@ export default class Auths extends React.Component {
authActions.logout(auths)
}
close =(e) => {
e.preventDefault()
let { authActions } = this.props
authActions.showDefinitions(false)
}
render() {
let { definitions, getComponent, authSelectors, errSelectors } = this.props
const AuthItem = getComponent("AuthItem")
@@ -74,6 +81,7 @@ 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>

View File

@@ -200,11 +200,11 @@ export default class Oauth2 extends React.Component {
<Row key={ name }>
<div className="checkbox">
<Input data-value={ name }
id={`${name}-checkbox-${this.state.name}`}
id={`${name}-${flow}-checkbox-${this.state.name}`}
disabled={ isAuthorized }
type="checkbox"
onChange={ this.onScopeChange }/>
<label htmlFor={`${name}-checkbox-${this.state.name}`}>
<label htmlFor={`${name}-${flow}-checkbox-${this.state.name}`}>
<span className="item"></span>
<div className="text">
<p className="name">{name}</p>

View File

@@ -27,6 +27,16 @@ export default class ContentType extends React.Component {
}
}
componentWillReceiveProps(nextProps) {
if(!nextProps.contentTypes || !nextProps.contentTypes.size) {
return
}
if(!nextProps.contentTypes.includes(nextProps.value)) {
nextProps.onChange(nextProps.contentTypes.first())
}
}
onChangeWrapper = e => this.props.onChange(e.target.value)
render() {
@@ -37,7 +47,7 @@ export default class ContentType extends React.Component {
return (
<div className={ "content-type-wrapper " + ( className || "" ) }>
<select className="content-type" value={value} onChange={this.onChangeWrapper} >
<select className="content-type" value={value || ""} onChange={this.onChangeWrapper} >
{ contentTypes.map( (val) => {
return <option key={ val } value={ val }>{ val }</option>
}).toArray()}

View File

@@ -1,6 +1,6 @@
import React from "react"
import PropTypes from "prop-types"
import Collapse from "react-collapse"
import { Collapse } from "react-collapse"
import { presets } from "react-motion"
import ObjectInspector from "react-object-inspector"
import Perf from "react-addons-perf"

View File

@@ -1,7 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import Collapse from "react-collapse"
import { Collapse } from "react-collapse"
export default class Errors extends React.Component {
@@ -113,7 +113,7 @@ const SpecErrorItem = ( { error, jumpToLine } ) => {
}
function toTitleCase(str) {
return str
return (str || "")
.split(" ")
.map(substr => substr[0].toUpperCase() + substr.slice(1))
.join(" ")

View File

@@ -8,7 +8,6 @@ export default class Execute extends Component {
specActions: PropTypes.object.isRequired,
operation: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
getComponent: PropTypes.func.isRequired,
method: PropTypes.string.isRequired,
onExecute: PropTypes.func
}

View File

@@ -2,20 +2,24 @@ import React from "react"
import PropTypes from "prop-types"
import Im from "immutable"
const propStyle = { color: "#999", fontStyle: "italic" }
export default class Headers extends React.Component {
static propTypes = {
headers: PropTypes.object.isRequired
headers: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
};
render() {
let { headers } = this.props
let { headers, getComponent } = this.props
const Property = getComponent("Property")
if ( !headers || !headers.size )
return null
return (
return (
<div className="headers-wrapper">
<h4 className="headers__title">Headers:</h4>
<table className="headers">
@@ -32,10 +36,13 @@ export default class Headers extends React.Component {
if(!Im.Map.isMap(header)) {
return null
}
const type = header.getIn(["schema"]) ? header.getIn(["schema", "type"]) : header.getIn(["type"])
const schemaExample = header.getIn(["schema", "example"])
return (<tr key={ key }>
<td className="header-col">{ key }</td>
<td className="header-col">{ header.get( "description" ) }</td>
<td className="header-col">{ header.get( "type" ) }</td>
<td className="header-col">{ type } { schemaExample ? <Property propKey={ "Example" } propVal={ schemaExample } propStyle={ propStyle } /> : null }</td>
</tr>)
}).toArray()
}

View File

@@ -1,6 +1,6 @@
import React from "react"
import PropTypes from "prop-types"
import OriCollapse from "react-collapse"
import { Collapse as OriCollapse } from "react-collapse"
function xclass(...args) {
return args.filter(a => !!a).join(" ").trim()
@@ -183,7 +183,7 @@ export class Select extends React.Component {
{ allowEmptyValue ? <option value="">--</option> : null }
{
allowedValues.map(function (item, key) {
return <option key={ key } value={ String(item) }>{ item }</option>
return <option key={ key } value={ String(item) }>{ String(item) }</option>
})
}
</select>

View File

@@ -94,8 +94,9 @@ export default class BaseLayout extends React.Component {
) : null }
{ servers && servers.size ? (
<div className="server-container">
<div className="global-server-container">
<Col className="servers wrapper" mobile={12}>
<span className="servers-title">Server</span>
<Servers
servers={servers}
currentServer={oas3Selectors.selectedServer()}

View File

@@ -1,6 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import ImPropTypes from "react-immutable-proptypes"
import { Iterable } from "immutable"
const Headers = ( { headers } )=>{
return (
@@ -28,19 +29,29 @@ Duration.propTypes = {
export default class LiveResponse extends React.Component {
static propTypes = {
response: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
pathMethod: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
response: PropTypes.instanceOf(Iterable).isRequired,
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
displayRequestDuration: PropTypes.bool.isRequired,
specSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired
}
shouldComponentUpdate(nextProps) {
// BUG: props.response is always coming back as a new Immutable instance
// same issue as responses.jsx (tryItOutResponse)
return this.props.response !== nextProps.response
|| this.props.path !== nextProps.path
|| this.props.method !== nextProps.method
|| this.props.displayRequestDuration !== nextProps.displayRequestDuration
}
render() {
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, pathMethod } = this.props
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, path, method } = this.props
const { showMutatedRequest } = getConfigs()
const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(pathMethod[0], pathMethod[1]) : specSelectors.requestFor(pathMethod[0], pathMethod[1])
const curlRequest = showMutatedRequest ? specSelectors.mutatedRequestFor(path, method) : specSelectors.requestFor(path, method)
const status = response.get("status")
const url = response.get("url")
const headers = response.get("headers").toJS()
@@ -118,7 +129,6 @@ export default class LiveResponse extends React.Component {
static propTypes = {
getComponent: PropTypes.func.isRequired,
request: ImPropTypes.map,
response: ImPropTypes.map
}
}

View File

@@ -53,6 +53,7 @@ export default class ModelExample extends React.Component {
{
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
expandDepth={ defaultModelExpandDepth }
specPath={specPath} />

View File

@@ -6,18 +6,17 @@ export default class ModelComponent extends Component {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
expandDepth: PropTypes.number
}
render(){
let { getComponent } = this.props
let { getComponent, getConfigs } = this.props
const Model = getComponent("Model")
return <div className="model-box">
<Model { ...this.props } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
<Model { ...this.props } getConfigs={ getConfigs } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
</div>
}
}

View File

@@ -1,10 +1,12 @@
import React, { Component } from "react"
import React, { PureComponent } from "react"
import ImPropTypes from "react-immutable-proptypes"
import PropTypes from "prop-types"
export default class Model extends Component {
export default class Model extends PureComponent {
static propTypes = {
schema: PropTypes.object.isRequired,
schema: ImPropTypes.orderedMap.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
@@ -30,7 +32,7 @@ export default class Model extends Component {
}
render () {
let { getComponent, specSelectors, schema, required, name, isRef, specPath } = this.props
let { getComponent, getConfigs, specSelectors, schema, required, name, isRef, specPath } = this.props
const ObjectModel = getComponent("ObjectModel")
const ArrayModel = getComponent("ArrayModel")
const PrimitiveModel = getComponent("PrimitiveModel")
@@ -55,6 +57,7 @@ export default class Model extends Component {
return <ObjectModel
className="object" { ...this.props }
specPath={specPath}
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}
@@ -62,6 +65,7 @@ export default class Model extends Component {
case "array":
return <ArrayModel
className="array" { ...this.props }
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}
@@ -74,6 +78,7 @@ export default class Model extends Component {
return <PrimitiveModel
{ ...this.props }
getComponent={ getComponent }
getConfigs={ getConfigs }
schema={ schema }
name={ name }
deprecated={deprecated}

View File

@@ -38,6 +38,7 @@ export default class Models extends Component {
schema={ model }
specPath={[...specPathBase, name]}
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }/>
</div>
}).toArray()

View File

@@ -9,6 +9,7 @@ export default class ObjectModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
@@ -18,9 +19,15 @@ export default class ObjectModel extends Component {
}
render(){
let { schema, name, isRef, getComponent, depth, specPath, expandDepth, ...otherProps } = this.props
let { schema, name, isRef, getComponent, getConfigs, depth, specPath, expandDepth, ...otherProps } = this.props
let { specSelectors } = otherProps
if(!schema) {
return null
}
const { showExtensions } = getConfigs()
let description = schema.get("description")
let properties = schema.get("properties")
let additionalProperties = schema.get("additionalProperties")
@@ -71,13 +78,14 @@ export default class ObjectModel extends Component {
{
!(properties && properties.size) ? null : properties.entrySeq().map(
([key, value]) => {
let isDeprecated = isOAS3() && value.get("deprecated")
let isRequired = List.isList(requiredProperties) && requiredProperties.contains(key)
let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" }
if ( isRequired ) {
propertyStyle.fontWeight = "bold"
}
return (<tr key={key}>
return (<tr key={key} className={isDeprecated && "deprecated"}>
<td style={ propertyStyle }>
{ key }{ isRequired && <span style={{ color: "red" }}>*</span> }
</td>
@@ -86,12 +94,37 @@ export default class ObjectModel extends Component {
required={ isRequired }
getComponent={ getComponent }
specPath={[...specPath, "properties", key]}
getConfigs={ getConfigs }
schema={ value }
depth={ depth + 1 } />
</td>
</tr>)
}).toArray()
}
{
// empty row befor extensions...
!showExtensions ? null : <tr>&nbsp;</tr>
}
{
!showExtensions ? null :
schema.entrySeq().map(
([key, value]) => {
if(key.slice(0,2) !== "x-") {
return
}
const normalizedValue = !value ? null : value.toJS ? value.toJS() : value
return (<tr key={key} style={{ color: "#777" }}>
<td>
{ key }
</td>
<td style={{ verticalAlign: "top" }}>
{ JSON.stringify(normalizedValue) }
</td>
</tr>)
}).toArray()
}
{
!additionalProperties || !additionalProperties.size ? null
: <tr>
@@ -100,6 +133,7 @@ export default class ObjectModel extends Component {
<Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "additionalProperties"]}
getConfigs={ getConfigs }
schema={ additionalProperties }
depth={ depth + 1 } />
</td>
@@ -114,6 +148,7 @@ export default class ObjectModel extends Component {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "anyOf", k]}
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
})}
@@ -129,6 +164,7 @@ export default class ObjectModel extends Component {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "oneOf", k]}
getConfigs={ getConfigs }
schema={ schema }
depth={ depth + 1 } /></div>
})}
@@ -140,13 +176,15 @@ export default class ObjectModel extends Component {
: <tr>
<td>{ "not ->" }</td>
<td>
{not.map((schema, k) => {
return <div key={k}><Model { ...otherProps } required={ false }
getComponent={ getComponent }
specPath={[...specPath, "not", k]}
schema={ schema }
depth={ depth + 1 } /></div>
})}
<div>
<Model { ...otherProps }
required={ false }
getComponent={ getComponent }
specPath={[...specPath, "not"]}
getConfigs={ getConfigs }
schema={ not }
depth={ depth + 1 } />
</div>
</td>
</tr>
}

View File

@@ -0,0 +1,17 @@
import React from "react"
import PropTypes from "prop-types"
export const OperationExtRow = ({ xKey, xVal }) => {
const xNormalizedValue = !xVal ? null : xVal.toJS ? xVal.toJS() : xVal
return (<tr>
<td>{ xKey }</td>
<td>{ JSON.stringify(xNormalizedValue) }</td>
</tr>)
}
OperationExtRow.propTypes = {
xKey: PropTypes.string,
xVal: PropTypes.any
}
export default OperationExtRow

View File

@@ -0,0 +1,35 @@
import React from "react"
import PropTypes from "prop-types"
export const OperationExt = ({ extensions, getComponent }) => {
let OperationExtRow = getComponent("OperationExtRow")
return (
<div className="opblock-section">
<div className="opblock-section-header">
<h4>Extensions</h4>
</div>
<div className="table-container">
<table>
<thead>
<tr>
<td className="col col_header">Field</td>
<td className="col col_header">Value</td>
</tr>
</thead>
<tbody>
{
extensions.entrySeq().map(([k, v]) => <OperationExtRow key={`${k}-${v}`} xKey={k} xVal={v} />)
}
</tbody>
</table>
</div>
</div>
)
}
OperationExt.propTypes = {
extensions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
export default OperationExt

View File

@@ -1,139 +1,95 @@
import React, { PureComponent } from "react"
import PropTypes from "prop-types"
import { getList } from "core/utils"
import * as CustomPropTypes from "core/proptypes"
import { sanitizeUrl } from "core/utils"
//import "less/opblock"
import { getExtensions, sanitizeUrl } from "core/utils"
import { Iterable } from "immutable"
export default class Operation extends PureComponent {
static propTypes = {
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
operation: PropTypes.object.isRequired,
showSummary: PropTypes.bool,
isShownKey: CustomPropTypes.arrayOrString.isRequired,
specPath: PropTypes.array.isRequired,
operation: PropTypes.instanceOf(Iterable).isRequired,
response: PropTypes.instanceOf(Iterable),
request: PropTypes.instanceOf(Iterable),
allowTryItOut: PropTypes.bool,
displayOperationId: PropTypes.bool,
displayRequestDuration: PropTypes.bool,
response: PropTypes.object,
request: PropTypes.object,
toggleShown: PropTypes.func.isRequired,
onTryoutClick: PropTypes.func.isRequired,
onCancelClick: PropTypes.func.isRequired,
onExecute: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
authActions: PropTypes.object,
authSelectors: PropTypes.object,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
oas3Selectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired,
getConfigs: PropTypes.func.isRequired
fn: PropTypes.object.isRequired
}
static defaultProps = {
showSummary: true,
operation: null,
response: null,
allowTryItOut: true,
displayOperationId: false,
displayRequestDuration: false
}
constructor(props, context) {
super(props, context)
this.state = {
tryItOutEnabled: false
}
}
componentWillReceiveProps(nextProps) {
const defaultContentType = "application/json"
let { specActions, path, method, operation } = nextProps
let producesValue = operation.get("produces_value")
let produces = operation.get("produces")
let consumes = operation.get("consumes")
let consumesValue = operation.get("consumes_value")
if(nextProps.response !== this.props.response) {
this.setState({ executeInProgress: false })
}
if (producesValue === undefined) {
producesValue = produces && produces.size ? produces.first() : defaultContentType
specActions.changeProducesValue([path, method], producesValue)
}
if (consumesValue === undefined) {
consumesValue = consumes && consumes.size ? consumes.first() : defaultContentType
specActions.changeConsumesValue([path, method], consumesValue)
}
}
toggleShown =() => {
let { layoutActions, isShownKey } = this.props
layoutActions.show(isShownKey, !this.isShown())
}
isShown =() => {
let { layoutSelectors, isShownKey, getConfigs } = this.props
let { docExpansion } = getConfigs()
return layoutSelectors.isShown(isShownKey, docExpansion === "full" ) // Here is where we set the default
}
onTryoutClick =() => {
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
}
onCancelClick =() => {
let { specActions, path, method } = this.props
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
specActions.clearValidateParams([path, method])
}
onExecute = () => {
this.setState({ executeInProgress: true })
request: null
}
render() {
let {
isShownKey,
specPath,
path,
method,
operation,
showSummary,
response,
request,
allowTryItOut,
displayOperationId,
displayRequestDuration,
toggleShown,
onTryoutClick,
onCancelClick,
onExecute,
fn,
getComponent,
getConfigs,
specActions,
specSelectors,
authActions,
authSelectors,
getConfigs,
oas3Actions
oas3Actions,
oas3Selectors
} = this.props
let operationProps = this.props.operation
let summary = operation.get("summary")
let description = operation.get("description")
let deprecated = operation.get("deprecated")
let externalDocs = operation.get("externalDocs")
let {
isShown,
isAuthorized,
jumpToKey,
path,
method,
op,
tag,
showSummary,
operationId,
allowTryItOut,
displayOperationId,
displayRequestDuration,
isDeepLinkingEnabled,
tryItOutEnabled,
executeInProgress
} = operationProps.toJS()
let {
summary,
description,
deprecated,
externalDocs,
schemes
} = op.operation
let operation = operationProps.getIn(["op", "operation"])
let security = operationProps.get("security")
let responses = operation.get("responses")
let security = operation.get("security") || specSelectors.security()
let produces = operation.get("produces")
let schemes = operation.get("schemes")
let parameters = getList(operation, ["parameters"])
let operationId = operation.get("__originalOperationId")
let operationScheme = specSelectors.operationScheme(path, method)
let isShownKey = ["operations", tag, operationId]
let extensions = getExtensions(operation)
const Responses = getComponent("responses")
const Parameters = getComponent( "parameters" )
@@ -144,10 +100,10 @@ export default class Operation extends PureComponent {
const Collapse = getComponent( "Collapse" )
const Markdown = getComponent( "Markdown" )
const Schemes = getComponent( "schemes" )
const OperationServers = getComponent( "OperationServers" )
const OperationExt = getComponent( "OperationExt" )
const { deepLinking } = getConfigs()
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
const { showExtensions } = getConfigs()
// Merge in Live Response
if(responses && response && response.size > 0) {
@@ -155,19 +111,17 @@ export default class Operation extends PureComponent {
response = response.set("notDocumented", notDocumented)
}
let { tryItOutEnabled } = this.state
let shown = this.isShown()
let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )
return (
<div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey.join("-")} >
<div className={`opblock-summary opblock-summary-${method}`} onClick={this.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={`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={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
<a
className="nostyle"
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null}
href={isDeepLinkingEnabled ? `#/${isShownKey[1]}/${isShownKey[2]}` : null}>
href={isDeepLinkingEnabled ? `#/${isShownKey.join("/")}` : null}>
<span>{path}</span>
</a>
<JumpToPath path={specPath} /> {/*TODO: use wrapComponents here, swagger-ui doesn't care about jumpToPath */}
@@ -183,13 +137,17 @@ export default class Operation extends PureComponent {
{
(!security || !security.count()) ? null :
<AuthorizeOperationBtn authActions={ authActions }
security={ security }
authSelectors={ authSelectors }/>
<AuthorizeOperationBtn
isAuthorized={ isAuthorized }
onClick={() => {
const applicableDefinitions = authSelectors.definitionsForRequirements(security)
authActions.showDefinitions(applicableDefinitions)
}}
/>
}
</div>
<Collapse isOpened={shown}>
<Collapse isOpened={isShown}>
<div className="opblock-body">
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
{ description &&
@@ -200,24 +158,25 @@ export default class Operation extends PureComponent {
</div>
}
{
externalDocs && externalDocs.get("url") ?
externalDocs && externalDocs.url ?
<div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs">
<span className="opblock-external-docs__description">
<Markdown source={ externalDocs.get("description") } />
<Markdown source={ externalDocs.description } />
</span>
<a className="opblock-external-docs__link" href={ sanitizeUrl(externalDocs.get("url")) }>{ externalDocs.get("url") }</a>
<a target="_blank" className="opblock-external-docs__link" href={ sanitizeUrl(externalDocs.url) }>{ externalDocs.url }</a>
</div>
</div> : null
}
<Parameters
parameters={parameters}
specPath={[...specPath, "parameters"]}
operation={operation}
onChangeKey={onChangeKey}
onTryoutClick = { this.onTryoutClick }
onCancelClick = { this.onCancelClick }
onTryoutClick = { onTryoutClick }
onCancelClick = { onCancelClick }
tryItOutEnabled = { tryItOutEnabled }
allowTryItOut={allowTryItOut}
@@ -229,6 +188,21 @@ export default class Operation extends PureComponent {
getConfigs={ getConfigs }
/>
{ !tryItOutEnabled ? null :
<OperationServers
getComponent={getComponent}
path={path}
method={method}
operationServers={operation.get("servers")}
pathServers={specSelectors.paths().getIn([path, "servers"])}
getSelectedServer={oas3Selectors.selectedServer}
setSelectedServer={oas3Actions.setSelectedServer}
setServerVariableValue={oas3Actions.setServerVariableValue}
getServerVariable={oas3Selectors.serverVariableValue}
getEffectiveServerValue={oas3Selectors.serverEffectiveValue}
/>
}
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
<Schemes schemes={ schemes }
path={ path }
@@ -242,25 +216,23 @@ export default class Operation extends PureComponent {
{ !tryItOutEnabled || !allowTryItOut ? null :
<Execute
getComponent={getComponent}
operation={ operation }
specActions={ specActions }
specSelectors={ specSelectors }
path={ path }
method={ method }
onExecute={ this.onExecute } />
onExecute={ onExecute } />
}
{ (!tryItOutEnabled || !response || !allowTryItOut) ? null :
<Clear
onClick={ this.onClearClick }
specActions={ specActions }
path={ path }
method={ method }/>
}
</div>
{this.state.executeInProgress ? <div className="loading-container"><div className="loading"></div></div> : null}
{executeInProgress ? <div className="loading-container"><div className="loading"></div></div> : null}
{ !responses ? null :
<Responses
@@ -274,11 +246,16 @@ export default class Operation extends PureComponent {
specActions={ specActions }
produces={ produces }
producesValue={ operation.get("produces_value") }
pathMethod={ [path, method] }
specPath={[...specPath, "responses"]}
path={ path }
method={ method }
displayRequestDuration={ displayRequestDuration }
fn={fn} />
}
{ !showExtensions || !extensions.size ? null :
<OperationExt extensions={ extensions } getComponent={ getComponent } />
}
</div>
</Collapse>
</div>

View File

@@ -1,8 +1,13 @@
import React from "react"
import PropTypes from "prop-types"
import { helpers } from "swagger-client"
import { createDeepLinkPath, sanitizeUrl } from "core/utils"
const { opId } = helpers
const SWAGGER2_OPERATION_METHODS = [
"get", "put", "post", "delete", "options", "head", "patch"
]
const OAS3_OPERATION_METHODS = SWAGGER2_OPERATION_METHODS.concat(["trace"])
export default class Operations extends React.Component {
@@ -21,28 +26,20 @@ export default class Operations extends React.Component {
render() {
let {
specSelectors,
specActions,
oas3Actions,
getComponent,
layoutSelectors,
layoutActions,
authActions,
authSelectors,
getConfigs,
fn
getConfigs
} = this.props
let taggedOps = specSelectors.taggedOperations()
const Operation = getComponent("operation")
const OperationContainer = getComponent("OperationContainer", true)
const Collapse = getComponent("Collapse")
const Markdown = getComponent("Markdown")
let showSummary = layoutSelectors.showSummary()
let {
docExpansion,
displayOperationId,
displayRequestDuration,
maxDisplayedTags,
deepLinking
} = getConfigs()
@@ -120,47 +117,30 @@ export default class Operations extends React.Component {
<Collapse isOpened={showTag}>
{
operations.map( op => {
const path = op.get("path", "")
const method = op.get("method", "")
const path = op.get("path")
const method = op.get("method")
const specPath = ["paths", path, method]
const operationId =
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
const isShownKey = ["operations", createDeepLinkPath(tag), createDeepLinkPath(operationId)]
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
const response = specSelectors.responseFor(op.get("path"), op.get("method"))
const request = specSelectors.requestFor(op.get("path"), op.get("method"))
// FIXME: (someday) this logic should probably be in a selector,
// but doing so would require further opening up
// selectors to the plugin system, to allow for dynamic
// overriding of low-level selectors that other selectors
// rely on. --KS, 12/17
const validMethods = specSelectors.isOAS3() ?
OAS3_OPERATION_METHODS : SWAGGER2_OPERATION_METHODS
return <Operation
{...op.toObject()}
if(validMethods.indexOf(method) === -1) {
return null
}
isShownKey={isShownKey}
return <OperationContainer
key={`${path}-${method}`}
specPath={specPath}
showSummary={showSummary}
key={isShownKey}
response={ response }
request={ request }
allowTryItOut={allowTryItOut}
displayOperationId={displayOperationId}
displayRequestDuration={displayRequestDuration}
specActions={ specActions }
specSelectors={ specSelectors }
oas3Actions={oas3Actions}
layoutActions={ layoutActions }
layoutSelectors={ layoutSelectors }
authActions={ authActions }
authSelectors={ authSelectors }
getComponent={ getComponent }
fn={fn}
getConfigs={ getConfigs }
op={op}
path={path}
method={method}
tag={tag}
/>
}).toArray()
}

View File

@@ -0,0 +1,12 @@
import React from "react"
import PropTypes from "prop-types"
export const ParameterExt = ({ xKey, xVal }) => {
return <div className="parameter__extension">{ xKey }: { String(xVal) }</div>
}
ParameterExt.propTypes = {
xKey: PropTypes.string,
xVal: PropTypes.any
}
export default ParameterExt

View File

@@ -2,6 +2,7 @@ import React, { Component } from "react"
import { Map } from "immutable"
import PropTypes from "prop-types"
import win from "core/window"
import { getExtensions } from "core/utils"
export default class ParameterRow extends Component {
static propTypes = {
@@ -73,6 +74,8 @@ export default class ParameterRow extends Component {
let { isOAS3 } = specSelectors
const { showExtensions } = getConfigs()
// const onChangeWrapper = (value) => onChange(param, value)
const JsonSchemaForm = getComponent("JsonSchemaForm")
const ParamBody = getComponent("ParamBody")
@@ -92,6 +95,7 @@ export default class ParameterRow extends Component {
const ModelExample = getComponent("modelExample")
const Markdown = getComponent("Markdown")
const ParameterExt = getComponent("ParameterExt")
let schema = param.get("schema")
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
@@ -101,6 +105,7 @@ export default class ParameterRow extends Component {
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : ""
let extensions = getExtensions(param)
return (
<tr>
@@ -114,6 +119,7 @@ export default class ParameterRow extends Component {
{ isOAS3 && isOAS3() && param.get("deprecated") ? "deprecated": null }
</div>
<div className="parameter__in">({ param.get("in") })</div>
{ !showExtensions || !extensions.size ? null : extensions.map((v, key) => <ParameterExt key={`${key}-${v}`} xKey={key} xVal={v} /> )}
</td>
<td className="col parameters-col_description">

View File

@@ -1,5 +1,6 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
import { getExtensions } from "core/utils"
const propStyle = { color: "#999", fontStyle: "italic" }
@@ -7,12 +8,15 @@ export default class Primitive extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
name: PropTypes.string,
depth: PropTypes.number
}
render(){
let { schema, getComponent, name, depth } = this.props
let { schema, getComponent, getConfigs, name, depth } = this.props
const { showExtensions } = getConfigs()
if(!schema || !schema.get) {
// don't render if schema isn't correctly formed
@@ -25,7 +29,10 @@ export default class Primitive extends Component {
let enumArray = schema.get("enum")
let title = schema.get("title") || name
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
let extensions = getExtensions(schema)
let properties = schema
.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
.filterNot( (v, key) => extensions.has(key) )
const Markdown = getComponent("Markdown")
const EnumModel = getComponent("EnumModel")
const Property = getComponent("Property")
@@ -38,6 +45,9 @@ export default class Primitive extends Component {
{
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null
}
{
showExtensions && extensions.size ? extensions.entrySeq().map( ( [ key, v ] ) => <Property key={`${key}-${v}`} propKey={ key } propVal={ v } propStyle={ propStyle } />) : null
}
{
!description ? null :
<Markdown source={ description } />

View File

@@ -32,7 +32,8 @@ export default class ResponseBody extends React.Component {
// XML
} else if (/xml/i.test(contentType)) {
body = formatXml(content, {
textNodesOnSameLine: true
textNodesOnSameLine: true,
indentor: " "
})
bodyEl = <HighlightCode value={ body } />
@@ -56,9 +57,6 @@ export default class ResponseBody extends React.Component {
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
let contentLength = headers["content-length"] || headers["Content-Length"]
if ( !(+contentLength) ) return null
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
if (!isSafari && "Blob" in window) {

View File

@@ -1,7 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import cx from "classnames"
import { fromJS, Seq } from "immutable"
import { fromJS, Seq, Iterable } from "immutable"
import { getSampleSchema, fromJSOrdered } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
@@ -42,7 +42,7 @@ export default class Response extends React.Component {
static propTypes = {
code: PropTypes.string.isRequired,
response: PropTypes.object,
response: PropTypes.instanceOf(Iterable),
className: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
@@ -159,7 +159,10 @@ export default class Response extends React.Component {
) : null}
{ headers ? (
<Headers headers={ headers }/>
<Headers
headers={ headers }
getComponent={ getComponent }
/>
) : null}

View File

@@ -1,42 +1,53 @@
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import { fromJS, Iterable } from "immutable"
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
export default class Responses extends React.Component {
static propTypes = {
request: PropTypes.object,
tryItOutResponse: PropTypes.object,
responses: PropTypes.object.isRequired,
produces: PropTypes.object,
tryItOutResponse: PropTypes.instanceOf(Iterable),
responses: PropTypes.instanceOf(Iterable).isRequired,
produces: PropTypes.instanceOf(Iterable),
producesValue: PropTypes.any,
displayRequestDuration: PropTypes.bool.isRequired,
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
specPath: PropTypes.array.isRequired,
displayRequestDuration: PropTypes.bool.isRequired,
fn: PropTypes.object.isRequired
}
static defaultProps = {
request: null,
tryItOutResponse: null,
produces: fromJS(["application/json"]),
displayRequestDuration: false
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
shouldComponentUpdate(nextProps) {
// BUG: props.tryItOutResponse is always coming back as a new Immutable instance
let render = this.props.tryItOutResponse !== nextProps.tryItOutResponse
|| this.props.responses !== nextProps.responses
|| this.props.produces !== nextProps.produces
|| this.props.producesValue !== nextProps.producesValue
|| this.props.displayRequestDuration !== nextProps.displayRequestDuration
|| this.props.path !== nextProps.path
|| this.props.method !== nextProps.method
return render
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)
onResponseContentTypeChange = ({ controlsAcceptHeader, value }) => {
const { oas3Actions, pathMethod } = this.props
const { oas3Actions, path, method } = this.props
if(controlsAcceptHeader) {
oas3Actions.setResponseContentType({
value,
pathMethod
path,
method
})
}
}
@@ -44,7 +55,6 @@ export default class Responses extends React.Component {
render() {
let {
responses,
request,
tryItOutResponse,
getComponent,
getConfigs,
@@ -83,12 +93,12 @@ export default class Responses extends React.Component {
{
!tryItOutResponse ? null
: <div>
<LiveResponse request={ request }
response={ tryItOutResponse }
<LiveResponse response={ tryItOutResponse }
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
pathMethod={ this.props.pathMethod }
path={ this.props.path }
method={ this.props.method }
displayRequestDuration={ displayRequestDuration } />
<h4>Responses</h4>
</div>