Update Operation content correctlybubble
@@ -45,6 +45,7 @@ | |||||
"brace": "0.7.0", | "brace": "0.7.0", | ||||
"classnames": "^2.2.5", | "classnames": "^2.2.5", | ||||
"commonmark": "^0.28.1", | "commonmark": "^0.28.1", | ||||
"core-js": "^2.5.1", | |||||
"css.escape": "1.5.1", | "css.escape": "1.5.1", | ||||
"deep-extend": "0.4.1", | "deep-extend": "0.4.1", | ||||
"expect": "1.20.2", | "expect": "1.20.2", | ||||
@@ -8,7 +8,6 @@ export default class Execute extends Component { | |||||
specActions: PropTypes.object.isRequired, | specActions: PropTypes.object.isRequired, | ||||
operation: PropTypes.object.isRequired, | operation: PropTypes.object.isRequired, | ||||
path: PropTypes.string.isRequired, | path: PropTypes.string.isRequired, | ||||
getComponent: PropTypes.func.isRequired, | |||||
method: PropTypes.string.isRequired, | method: PropTypes.string.isRequired, | ||||
onExecute: PropTypes.func | onExecute: PropTypes.func | ||||
} | } | ||||
@@ -1,6 +1,7 @@ | |||||
import React from "react" | import React from "react" | ||||
import PropTypes from "prop-types" | import PropTypes from "prop-types" | ||||
import ImPropTypes from "react-immutable-proptypes" | import ImPropTypes from "react-immutable-proptypes" | ||||
import { Iterable } from "immutable" | |||||
const Headers = ( { headers } )=>{ | const Headers = ( { headers } )=>{ | ||||
return ( | return ( | ||||
@@ -28,19 +29,29 @@ Duration.propTypes = { | |||||
export default class LiveResponse extends React.Component { | export default class LiveResponse extends React.Component { | ||||
static propTypes = { | static propTypes = { | ||||
response: PropTypes.object.isRequired, | |||||
response: PropTypes.instanceOf(Iterable).isRequired, | |||||
path: PropTypes.string.isRequired, | |||||
method: PropTypes.string.isRequired, | |||||
displayRequestDuration: PropTypes.bool.isRequired, | |||||
specSelectors: PropTypes.object.isRequired, | specSelectors: PropTypes.object.isRequired, | ||||
pathMethod: PropTypes.object.isRequired, | |||||
getComponent: PropTypes.func.isRequired, | getComponent: PropTypes.func.isRequired, | ||||
displayRequestDuration: PropTypes.bool.isRequired, | |||||
getConfigs: 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() { | render() { | ||||
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, pathMethod } = this.props | |||||
const { response, getComponent, getConfigs, displayRequestDuration, specSelectors, path, method } = this.props | |||||
const { showMutatedRequest } = getConfigs() | 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 status = response.get("status") | ||||
const url = response.get("url") | const url = response.get("url") | ||||
const headers = response.get("headers").toJS() | const headers = response.get("headers").toJS() | ||||
@@ -118,7 +129,6 @@ export default class LiveResponse extends React.Component { | |||||
static propTypes = { | static propTypes = { | ||||
getComponent: PropTypes.func.isRequired, | getComponent: PropTypes.func.isRequired, | ||||
request: ImPropTypes.map, | |||||
response: ImPropTypes.map | response: ImPropTypes.map | ||||
} | } | ||||
} | } |
@@ -1,32 +1,22 @@ | |||||
import React, { PureComponent } from "react" | import React, { PureComponent } from "react" | ||||
import PropTypes from "prop-types" | import PropTypes from "prop-types" | ||||
import { getList } from "core/utils" | import { getList } from "core/utils" | ||||
import * as CustomPropTypes from "core/proptypes" | |||||
import { sanitizeUrl } from "core/utils" | import { sanitizeUrl } from "core/utils" | ||||
//import "less/opblock" | |||||
import { Iterable } from "immutable" | |||||
export default class Operation extends PureComponent { | export default class Operation extends PureComponent { | ||||
static propTypes = { | static propTypes = { | ||||
path: PropTypes.string.isRequired, | |||||
method: PropTypes.string.isRequired, | |||||
operation: PropTypes.object.isRequired, | |||||
showSummary: PropTypes.bool, | |||||
isShown: PropTypes.bool.isRequired, | |||||
tagKey: PropTypes.string, | |||||
operationKey: PropTypes.string, | |||||
jumpToKey: CustomPropTypes.arrayOrString.isRequired, | |||||
allowTryItOut: PropTypes.bool, | |||||
operation: PropTypes.instanceOf(Iterable).isRequired, | |||||
response: PropTypes.instanceOf(Iterable), | |||||
request: PropTypes.instanceOf(Iterable), | |||||
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, | getComponent: PropTypes.func.isRequired, | ||||
getConfigs: PropTypes.func.isRequired, | |||||
authActions: PropTypes.object, | authActions: PropTypes.object, | ||||
authSelectors: PropTypes.object, | authSelectors: PropTypes.object, | ||||
specActions: PropTypes.object.isRequired, | specActions: PropTypes.object.isRequired, | ||||
@@ -34,88 +24,66 @@ export default class Operation extends PureComponent { | |||||
oas3Actions: PropTypes.object.isRequired, | oas3Actions: PropTypes.object.isRequired, | ||||
layoutActions: PropTypes.object.isRequired, | layoutActions: PropTypes.object.isRequired, | ||||
layoutSelectors: PropTypes.object.isRequired, | layoutSelectors: PropTypes.object.isRequired, | ||||
fn: PropTypes.object.isRequired, | |||||
getConfigs: PropTypes.func.isRequired | |||||
fn: PropTypes.object.isRequired | |||||
} | } | ||||
static defaultProps = { | static defaultProps = { | ||||
showSummary: true, | |||||
operation: null, | |||||
response: null, | response: null, | ||||
allowTryItOut: true, | |||||
displayOperationId: false, | |||||
displayRequestDuration: false | |||||
} | |||||
constructor(props, context) { | |||||
super(props, context) | |||||
this.state = { | |||||
tryItOutEnabled: false | |||||
} | |||||
} | |||||
componentWillReceiveProps(nextProps) { | |||||
if(nextProps.response !== this.props.response) { | |||||
this.setState({ executeInProgress: false }) | |||||
} | |||||
} | |||||
toggleShown =() => { | |||||
let { layoutActions, tagKey, operationKey, isShown } = this.props | |||||
const isShownKey = ["operations", tagKey, operationKey] | |||||
layoutActions.show(isShownKey, !isShown) | |||||
} | |||||
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() { | render() { | ||||
let { | let { | ||||
operationKey, | |||||
tagKey, | |||||
isShown, | |||||
jumpToKey, | |||||
path, | |||||
method, | |||||
operation, | |||||
showSummary, | |||||
response, | response, | ||||
request, | request, | ||||
allowTryItOut, | |||||
displayOperationId, | |||||
displayRequestDuration, | |||||
toggleShown, | |||||
onTryoutClick, | |||||
onCancelClick, | |||||
onExecute, | |||||
fn, | fn, | ||||
getComponent, | getComponent, | ||||
getConfigs, | |||||
specActions, | specActions, | ||||
specSelectors, | specSelectors, | ||||
authActions, | authActions, | ||||
authSelectors, | authSelectors, | ||||
getConfigs, | |||||
oas3Actions | oas3Actions | ||||
} = this.props | } = 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, | |||||
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 responses = operation.get("responses") | let responses = operation.get("responses") | ||||
let security = operation.get("security") || specSelectors.security() | |||||
let produces = operation.get("produces") | let produces = operation.get("produces") | ||||
let schemes = operation.get("schemes") | |||||
let security = operation.get("security") || specSelectors.security() | |||||
let parameters = getList(operation, ["parameters"]) | let parameters = getList(operation, ["parameters"]) | ||||
let operationId = operation.get("__originalOperationId") | |||||
let operationScheme = specSelectors.operationScheme(path, method) | let operationScheme = specSelectors.operationScheme(path, method) | ||||
let isShownKey = ["operations", tag, operationId] | |||||
const Responses = getComponent("responses") | const Responses = getComponent("responses") | ||||
const Parameters = getComponent( "parameters" ) | const Parameters = getComponent( "parameters" ) | ||||
@@ -127,28 +95,23 @@ export default class Operation extends PureComponent { | |||||
const Markdown = getComponent( "Markdown" ) | const Markdown = getComponent( "Markdown" ) | ||||
const Schemes = getComponent( "schemes" ) | const Schemes = getComponent( "schemes" ) | ||||
const { deepLinking } = getConfigs() | |||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false" | |||||
// Merge in Live Response | // Merge in Live Response | ||||
if(responses && response && response.size > 0) { | if(responses && response && response.size > 0) { | ||||
let notDocumented = !responses.get(String(response.get("status"))) | let notDocumented = !responses.get(String(response.get("status"))) | ||||
response = response.set("notDocumented", notDocumented) | response = response.set("notDocumented", notDocumented) | ||||
} | } | ||||
let { tryItOutEnabled } = this.state | |||||
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={deprecated ? "opblock opblock-deprecated" : isShown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={`operations-${tagKey}-${operationKey}`} > | |||||
<div className={`opblock-summary opblock-summary-${method}`} onClick={this.toggleShown} > | |||||
<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} > | |||||
<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 | ||||
className="nostyle" | className="nostyle" | ||||
onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null} | onClick={isDeepLinkingEnabled ? (e) => e.preventDefault() : null} | ||||
href={isDeepLinkingEnabled ? `#/${tagKey}/${operationKey}` : null}> | |||||
href={isDeepLinkingEnabled ? `#/${isShownKey.join("/")}` : null}> | |||||
<span>{path}</span> | <span>{path}</span> | ||||
</a> | </a> | ||||
<JumpToPath path={jumpToKey} /> | <JumpToPath path={jumpToKey} /> | ||||
@@ -200,8 +163,8 @@ export default class Operation extends PureComponent { | |||||
parameters={parameters} | parameters={parameters} | ||||
operation={operation} | operation={operation} | ||||
onChangeKey={onChangeKey} | onChangeKey={onChangeKey} | ||||
onTryoutClick = { this.onTryoutClick } | |||||
onCancelClick = { this.onCancelClick } | |||||
onTryoutClick = { onTryoutClick } | |||||
onCancelClick = { onCancelClick } | |||||
tryItOutEnabled = { tryItOutEnabled } | tryItOutEnabled = { tryItOutEnabled } | ||||
allowTryItOut={allowTryItOut} | allowTryItOut={allowTryItOut} | ||||
@@ -226,25 +189,23 @@ export default class Operation extends PureComponent { | |||||
{ !tryItOutEnabled || !allowTryItOut ? null : | { !tryItOutEnabled || !allowTryItOut ? null : | ||||
<Execute | <Execute | ||||
getComponent={getComponent} | |||||
operation={ operation } | operation={ operation } | ||||
specActions={ specActions } | specActions={ specActions } | ||||
specSelectors={ specSelectors } | specSelectors={ specSelectors } | ||||
path={ path } | path={ path } | ||||
method={ method } | method={ method } | ||||
onExecute={ this.onExecute } /> | |||||
onExecute={ onExecute } /> | |||||
} | } | ||||
{ (!tryItOutEnabled || !response || !allowTryItOut) ? null : | { (!tryItOutEnabled || !response || !allowTryItOut) ? null : | ||||
<Clear | <Clear | ||||
onClick={ this.onClearClick } | |||||
specActions={ specActions } | specActions={ specActions } | ||||
path={ path } | path={ path } | ||||
method={ method }/> | method={ method }/> | ||||
} | } | ||||
</div> | </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 ? null : | ||||
<Responses | <Responses | ||||
@@ -258,7 +219,8 @@ export default class Operation extends PureComponent { | |||||
specActions={ specActions } | specActions={ specActions } | ||||
produces={ produces } | produces={ produces } | ||||
producesValue={ operation.get("produces_value") } | producesValue={ operation.get("produces_value") } | ||||
pathMethod={ [path, method] } | |||||
path={ path } | |||||
method={ method } | |||||
displayRequestDuration={ displayRequestDuration } | displayRequestDuration={ displayRequestDuration } | ||||
fn={fn} /> | fn={fn} /> | ||||
} | } | ||||
@@ -1,8 +1,6 @@ | |||||
import React from "react" | import React from "react" | ||||
import PropTypes from "prop-types" | import PropTypes from "prop-types" | ||||
import { helpers } from "swagger-client" | |||||
import { createDeepLinkPath, sanitizeUrl } from "core/utils" | import { createDeepLinkPath, sanitizeUrl } from "core/utils" | ||||
const { opId } = helpers | |||||
export default class Operations extends React.Component { | export default class Operations extends React.Component { | ||||
@@ -21,28 +19,20 @@ export default class Operations extends React.Component { | |||||
render() { | render() { | ||||
let { | let { | ||||
specSelectors, | specSelectors, | ||||
specActions, | |||||
oas3Actions, | |||||
getComponent, | getComponent, | ||||
layoutSelectors, | layoutSelectors, | ||||
layoutActions, | layoutActions, | ||||
authActions, | |||||
authSelectors, | |||||
getConfigs, | |||||
fn | |||||
getConfigs | |||||
} = this.props | } = this.props | ||||
let taggedOps = specSelectors.taggedOperations() | let taggedOps = specSelectors.taggedOperations() | ||||
const Operation = getComponent("operation") | |||||
const OperationContainer = getComponent("OperationContainer", true) | |||||
const Collapse = getComponent("Collapse") | const Collapse = getComponent("Collapse") | ||||
const Markdown = getComponent("Markdown") | const Markdown = getComponent("Markdown") | ||||
let showSummary = layoutSelectors.showSummary() | |||||
let { | let { | ||||
docExpansion, | docExpansion, | ||||
displayOperationId, | |||||
displayRequestDuration, | |||||
maxDisplayedTags, | maxDisplayedTags, | ||||
deepLinking | deepLinking | ||||
} = getConfigs() | } = getConfigs() | ||||
@@ -120,49 +110,15 @@ export default class Operations extends React.Component { | |||||
<Collapse isOpened={showTag}> | <Collapse isOpened={showTag}> | ||||
{ | { | ||||
operations.map( op => { | operations.map( op => { | ||||
const path = op.get("path", "") | |||||
const method = op.get("method", "") | |||||
const jumpToKey = `paths.${path}.${method}` | |||||
const operationId = | |||||
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id") | |||||
const tagKey = createDeepLinkPath(tag) | |||||
const operationKey = 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")) | |||||
return <Operation | |||||
{...op.toObject()} | |||||
tagKey={tagKey} | |||||
operationKey={operationKey} | |||||
isShown={layoutSelectors.isShown(["operations", tagKey, operationKey], docExpansion === "full")} | |||||
jumpToKey={jumpToKey} | |||||
showSummary={showSummary} | |||||
key={tagKey + operationKey} | |||||
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 } | |||||
const path = op.get("path") | |||||
const method = op.get("method") | |||||
return <OperationContainer | |||||
key={`${path}-${method}`} | |||||
op={op} | |||||
path={path} | |||||
method={method} | |||||
tag={tag} | |||||
/> | /> | ||||
}).toArray() | }).toArray() | ||||
} | } | ||||
@@ -1,7 +1,7 @@ | |||||
import React from "react" | import React from "react" | ||||
import PropTypes from "prop-types" | import PropTypes from "prop-types" | ||||
import cx from "classnames" | import cx from "classnames" | ||||
import { fromJS, Seq } from "immutable" | |||||
import { fromJS, Seq, Iterable } from "immutable" | |||||
import { getSampleSchema, fromJSOrdered } from "core/utils" | import { getSampleSchema, fromJSOrdered } from "core/utils" | ||||
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => { | const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => { | ||||
@@ -42,7 +42,7 @@ export default class Response extends React.Component { | |||||
static propTypes = { | static propTypes = { | ||||
code: PropTypes.string.isRequired, | code: PropTypes.string.isRequired, | ||||
response: PropTypes.object, | |||||
response: PropTypes.instanceOf(Iterable), | |||||
className: PropTypes.string, | className: PropTypes.string, | ||||
getComponent: PropTypes.func.isRequired, | getComponent: PropTypes.func.isRequired, | ||||
getConfigs: PropTypes.func.isRequired, | getConfigs: PropTypes.func.isRequired, | ||||
@@ -1,41 +1,52 @@ | |||||
import React from "react" | import React from "react" | ||||
import PropTypes from "prop-types" | import PropTypes from "prop-types" | ||||
import { fromJS } from "immutable" | |||||
import { fromJS, Iterable } from "immutable" | |||||
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils" | import { defaultStatusCode, getAcceptControllingResponse } from "core/utils" | ||||
export default class Responses extends React.Component { | export default class Responses extends React.Component { | ||||
static propTypes = { | 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, | producesValue: PropTypes.any, | ||||
displayRequestDuration: PropTypes.bool.isRequired, | |||||
path: PropTypes.string.isRequired, | |||||
method: PropTypes.string.isRequired, | |||||
getComponent: PropTypes.func.isRequired, | getComponent: PropTypes.func.isRequired, | ||||
getConfigs: PropTypes.func.isRequired, | getConfigs: PropTypes.func.isRequired, | ||||
specSelectors: PropTypes.object.isRequired, | specSelectors: PropTypes.object.isRequired, | ||||
specActions: PropTypes.object.isRequired, | specActions: PropTypes.object.isRequired, | ||||
oas3Actions: PropTypes.object.isRequired, | oas3Actions: PropTypes.object.isRequired, | ||||
pathMethod: PropTypes.array.isRequired, | |||||
displayRequestDuration: PropTypes.bool.isRequired, | |||||
fn: PropTypes.object.isRequired | fn: PropTypes.object.isRequired | ||||
} | } | ||||
static defaultProps = { | static defaultProps = { | ||||
request: null, | |||||
tryItOutResponse: null, | tryItOutResponse: null, | ||||
produces: fromJS(["application/json"]), | produces: fromJS(["application/json"]), | ||||
displayRequestDuration: false | 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 }) => { | onResponseContentTypeChange = ({ controlsAcceptHeader, value }) => { | ||||
const { oas3Actions, pathMethod } = this.props | |||||
const { oas3Actions, path, method } = this.props | |||||
if(controlsAcceptHeader) { | if(controlsAcceptHeader) { | ||||
oas3Actions.setResponseContentType({ | oas3Actions.setResponseContentType({ | ||||
value, | value, | ||||
pathMethod | |||||
path, | |||||
method | |||||
}) | }) | ||||
} | } | ||||
} | } | ||||
@@ -43,7 +54,6 @@ export default class Responses extends React.Component { | |||||
render() { | render() { | ||||
let { | let { | ||||
responses, | responses, | ||||
request, | |||||
tryItOutResponse, | tryItOutResponse, | ||||
getComponent, | getComponent, | ||||
getConfigs, | getConfigs, | ||||
@@ -81,12 +91,12 @@ export default class Responses extends React.Component { | |||||
{ | { | ||||
!tryItOutResponse ? null | !tryItOutResponse ? null | ||||
: <div> | : <div> | ||||
<LiveResponse request={ request } | |||||
response={ tryItOutResponse } | |||||
<LiveResponse response={ tryItOutResponse } | |||||
getComponent={ getComponent } | getComponent={ getComponent } | ||||
getConfigs={ getConfigs } | getConfigs={ getConfigs } | ||||
specSelectors={ specSelectors } | specSelectors={ specSelectors } | ||||
pathMethod={ this.props.pathMethod } | |||||
path={ this.props.path } | |||||
method={ this.props.method } | |||||
displayRequestDuration={ displayRequestDuration } /> | displayRequestDuration={ displayRequestDuration } /> | ||||
<h4>Responses</h4> | <h4>Responses</h4> | ||||
</div> | </div> | ||||
@@ -0,0 +1,192 @@ | |||||
import React, { PureComponent } from "react" | |||||
import PropTypes from "prop-types" | |||||
import { helpers } from "swagger-client" | |||||
import { Iterable, fromJS } from "immutable" | |||||
const { opId } = helpers | |||||
export default class OperationContainer extends PureComponent { | |||||
constructor(props, context) { | |||||
super(props, context) | |||||
this.state = { | |||||
tryItOutEnabled: false, | |||||
executeInProgress: false | |||||
} | |||||
} | |||||
static propTypes = { | |||||
op: PropTypes.instanceOf(Iterable).isRequired, | |||||
tag: PropTypes.string.isRequired, | |||||
path: PropTypes.string.isRequired, | |||||
method: PropTypes.string.isRequired, | |||||
operationId: PropTypes.string.isRequired, | |||||
showSummary: PropTypes.bool.isRequired, | |||||
isShown: PropTypes.bool.isRequired, | |||||
jumpToKey: PropTypes.string.isRequired, | |||||
allowTryItOut: PropTypes.bool, | |||||
displayOperationId: PropTypes.bool, | |||||
displayRequestDuration: PropTypes.bool, | |||||
response: PropTypes.instanceOf(Iterable), | |||||
request: PropTypes.instanceOf(Iterable), | |||||
isDeepLinkingEnabled: PropTypes.bool.isRequired, | |||||
getComponent: PropTypes.func.isRequired, | |||||
authActions: PropTypes.object, | |||||
oas3Actions: PropTypes.object, | |||||
authSelectors: PropTypes.object, | |||||
specActions: PropTypes.object.isRequired, | |||||
specSelectors: PropTypes.object.isRequired, | |||||
layoutActions: PropTypes.object.isRequired, | |||||
layoutSelectors: PropTypes.object.isRequired, | |||||
fn: PropTypes.object.isRequired, | |||||
getConfigs: PropTypes.func.isRequired | |||||
} | |||||
static defaultProps = { | |||||
showSummary: true, | |||||
response: null, | |||||
allowTryItOut: true, | |||||
displayOperationId: false, | |||||
displayRequestDuration: false | |||||
} | |||||
mapStateToProps(nextState, props) { | |||||
const { op, layoutSelectors, getConfigs } = props | |||||
const { docExpansion, deepLinking, displayOperationId, displayRequestDuration } = getConfigs() | |||||
const showSummary = layoutSelectors.showSummary() | |||||
const operationId = op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), props.path, props.method) || op.get("id") | |||||
const isShownKey = ["operations", props.tag, operationId] | |||||
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false" | |||||
return { | |||||
operationId, | |||||
isDeepLinkingEnabled, | |||||
showSummary, | |||||
displayOperationId, | |||||
displayRequestDuration, | |||||
isShown: layoutSelectors.isShown(isShownKey, docExpansion === "full" ), | |||||
jumpToKey: `paths.${props.path}.${props.method}`, | |||||
allowTryItOut: props.specSelectors.allowTryItOutFor(props.path, props.method), | |||||
response: props.specSelectors.responseFor(props.path, props.method), | |||||
request: props.specSelectors.requestFor(props.path, props.method) | |||||
} | |||||
} | |||||
componentWillReceiveProps(nextProps) { | |||||
const defaultContentType = "application/json" | |||||
let { specActions, path, method, op } = nextProps | |||||
let operation = op.get("operation") | |||||
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, tag, operationId, isShown } = this.props | |||||
layoutActions.show(["operations", tag, operationId], !isShown) | |||||
} | |||||
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 }) | |||||
} | |||||
render() { | |||||
let { | |||||
op, | |||||
tag, | |||||
path, | |||||
method, | |||||
operationId, | |||||
showSummary, | |||||
isShown, | |||||
jumpToKey, | |||||
allowTryItOut, | |||||
response, | |||||
request, | |||||
displayOperationId, | |||||
displayRequestDuration, | |||||
isDeepLinkingEnabled, | |||||
specSelectors, | |||||
specActions, | |||||
getComponent, | |||||
getConfigs, | |||||
layoutSelectors, | |||||
layoutActions, | |||||
authActions, | |||||
authSelectors, | |||||
oas3Actions, | |||||
fn | |||||
} = this.props | |||||
const Operation = getComponent( "operation" ) | |||||
const operationProps = fromJS({ | |||||
op, | |||||
tag, | |||||
path, | |||||
method, | |||||
operationId, | |||||
showSummary, | |||||
isShown, | |||||
jumpToKey, | |||||
allowTryItOut, | |||||
request, | |||||
displayOperationId, | |||||
displayRequestDuration, | |||||
isDeepLinkingEnabled, | |||||
executeInProgress: this.state.executeInProgress, | |||||
tryItOutEnabled: this.state.tryItOutEnabled | |||||
}) | |||||
return ( | |||||
<Operation | |||||
operation={operationProps} | |||||
response={response} | |||||
request={request} | |||||
isShown={isShown} | |||||
toggleShown={this.toggleShown} | |||||
onTryoutClick={this.onTryoutClick} | |||||
onCancelClick={this.onCancelClick} | |||||
onExecute={this.onExecute} | |||||
specActions={ specActions } | |||||
specSelectors={ specSelectors } | |||||
oas3Actions={oas3Actions} | |||||
layoutActions={ layoutActions } | |||||
layoutSelectors={ layoutSelectors } | |||||
authActions={ authActions } | |||||
authSelectors={ authSelectors } | |||||
getComponent={ getComponent } | |||||
getConfigs={ getConfigs } | |||||
fn={fn} | |||||
/> | |||||
) | |||||
} | |||||
} |
@@ -7,8 +7,7 @@ import * as AllPlugins from "core/plugins/all" | |||||
import { parseSearch } from "core/utils" | import { parseSearch } from "core/utils" | ||||
if (process.env.NODE_ENV !== "production") { | if (process.env.NODE_ENV !== "production") { | ||||
const Perf = require("react-addons-perf") | |||||
window.Perf = Perf | |||||
window.Perf = require("react-addons-perf") | |||||
} | } | ||||
// eslint-disable-next-line no-undef | // eslint-disable-next-line no-undef | ||||
@@ -28,10 +28,10 @@ export function setRequestContentType ({ value, pathMethod }) { | |||||
} | } | ||||
} | } | ||||
export function setResponseContentType ({ value, pathMethod }) { | |||||
export function setResponseContentType ({ value, path, method }) { | |||||
return { | return { | ||||
type: UPDATE_RESPONSE_CONTENT_TYPE, | type: UPDATE_RESPONSE_CONTENT_TYPE, | ||||
payload: { value, pathMethod } | |||||
payload: { value, path, method } | |||||
} | } | ||||
} | } | ||||
@@ -18,8 +18,7 @@ export default { | |||||
let [path, method] = pathMethod | let [path, method] = pathMethod | ||||
return state.setIn( [ "requestData", path, method, "requestContentType" ], value) | return state.setIn( [ "requestData", path, method, "requestContentType" ], value) | ||||
}, | }, | ||||
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, pathMethod } } ) =>{ | |||||
let [path, method] = pathMethod | |||||
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, path, method } } ) =>{ | |||||
return state.setIn( [ "requestData", path, method, "responseContentType" ], value) | return state.setIn( [ "requestData", path, method, "responseContentType" ], value) | ||||
}, | }, | ||||
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{ | [UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{ | ||||
@@ -20,8 +20,14 @@ const RootWrapper = (reduxStore, ComponentToWrap) => class extends Component { | |||||
} | } | ||||
const makeContainer = (getSystem, component, reduxStore) => { | const makeContainer = (getSystem, component, reduxStore) => { | ||||
const mapStateToProps = function(state, ownProps) { | |||||
const propsForContainerComponent = Object.assign({}, ownProps, getSystem()) | |||||
const ori = component.prototype.mapStateToProps || (state => { return {state} }) | |||||
return ori(state, propsForContainerComponent) | |||||
} | |||||
let wrappedWithSystem = SystemWrapper(getSystem, component, reduxStore) | let wrappedWithSystem = SystemWrapper(getSystem, component, reduxStore) | ||||
let connected = connect(state => ({state}))(wrappedWithSystem) | |||||
let connected = connect( mapStateToProps )(wrappedWithSystem) | |||||
if(reduxStore) | if(reduxStore) | ||||
return RootWrapper(reduxStore, connected) | return RootWrapper(reduxStore, connected) | ||||
return connected | return connected | ||||
@@ -13,6 +13,8 @@ import downloadUrlPlugin from "core/plugins/download-url" | |||||
import configsPlugin from "plugins/configs" | import configsPlugin from "plugins/configs" | ||||
import deepLinkingPlugin from "core/plugins/deep-linking" | import deepLinkingPlugin from "core/plugins/deep-linking" | ||||
import OperationContainer from "core/containers/OperationContainer" | |||||
import App from "core/components/app" | import App from "core/components/app" | ||||
import AuthorizationPopup from "core/components/auth/authorization-popup" | import AuthorizationPopup from "core/components/auth/authorization-popup" | ||||
import AuthorizeBtn from "core/components/auth/authorize-btn" | import AuthorizeBtn from "core/components/auth/authorize-btn" | ||||
@@ -112,7 +114,8 @@ export default function() { | |||||
TryItOutButton, | TryItOutButton, | ||||
Markdown, | Markdown, | ||||
BaseLayout, | BaseLayout, | ||||
VersionStamp | |||||
VersionStamp, | |||||
OperationContainer | |||||
} | } | ||||
} | } | ||||
@@ -289,8 +289,7 @@ export default class Store { | |||||
getMapStateToProps() { | getMapStateToProps() { | ||||
return () => { | return () => { | ||||
let obj = Object.assign({}, this.getSystem()) | |||||
return obj | |||||
return Object.assign({}, this.getSystem()) | |||||
} | } | ||||
} | } | ||||
@@ -1,7 +1,11 @@ | |||||
/* eslint-env mocha */ | /* eslint-env mocha */ | ||||
import React, { PureComponent } from "react" | |||||
import expect from "expect" | import expect from "expect" | ||||
import System from "core/system" | import System from "core/system" | ||||
import { fromJS } from "immutable" | import { fromJS } from "immutable" | ||||
import { render } from "enzyme" | |||||
import ViewPlugin from "core/plugins/view/index.js" | |||||
import { connect, Provider } from "react-redux" | |||||
describe("bound system", function(){ | describe("bound system", function(){ | ||||
@@ -444,4 +448,129 @@ describe("bound system", function(){ | |||||
}) | }) | ||||
describe("getComponent", function() { | |||||
it("returns a component from the system", function() { | |||||
const system = new System({ | |||||
plugins: [ | |||||
ViewPlugin, | |||||
{ | |||||
components: { | |||||
test: ({ name }) => <div>{name} component</div> | |||||
} | |||||
} | |||||
] | |||||
}) | |||||
// When | |||||
var Component = system.getSystem().getComponent("test") | |||||
const renderedComponent = render(<Component name="Test" />) | |||||
expect(renderedComponent.text()).toEqual("Test component") | |||||
}) | |||||
it("allows container components to provide their own `mapStateToProps` function", function() { | |||||
// Given | |||||
class ContainerComponent extends PureComponent { | |||||
mapStateToProps(nextState, props) { | |||||
return { | |||||
"fromMapState": "This came from mapStateToProps" | |||||
} | |||||
} | |||||
static defaultProps = { | |||||
"fromMapState" : "" | |||||
} | |||||
render() { | |||||
const { exampleSelectors, fromMapState, fromOwnProps } = this.props | |||||
return ( | |||||
<div>{ fromMapState } {exampleSelectors.foo()} {fromOwnProps}</div> | |||||
) | |||||
} | |||||
} | |||||
const system = new System({ | |||||
plugins: [ | |||||
ViewPlugin, | |||||
{ | |||||
components: { | |||||
ContainerComponent | |||||
} | |||||
}, | |||||
{ | |||||
statePlugins: { | |||||
example: { | |||||
selectors: { | |||||
foo() { return "and this came from the system" } | |||||
} | |||||
} | |||||
} | |||||
} | |||||
] | |||||
}) | |||||
// When | |||||
var Component = system.getSystem().getComponent("ContainerComponent", true) | |||||
const renderedComponent = render( | |||||
<Provider store={system.getStore()}> | |||||
<Component fromOwnProps="and this came from my own props" /> | |||||
</Provider> | |||||
) | |||||
// Then | |||||
expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props") | |||||
}) | |||||
it("gives the system and own props as props to a container's `mapStateToProps` function", function() { | |||||
// Given | |||||
class ContainerComponent extends PureComponent { | |||||
mapStateToProps(nextState, props) { | |||||
const { exampleSelectors, fromMapState, fromOwnProps } = props | |||||
return { | |||||
"fromMapState": `This came from mapStateToProps ${exampleSelectors.foo()} ${fromOwnProps}` | |||||
} | |||||
} | |||||
static defaultProps = { | |||||
"fromMapState" : "" | |||||
} | |||||
render() { | |||||
const { fromMapState } = this.props | |||||
return ( | |||||
<div>{ fromMapState }</div> | |||||
) | |||||
} | |||||
} | |||||
const system = new System({ | |||||
plugins: [ | |||||
ViewPlugin, | |||||
{ | |||||
components: { | |||||
ContainerComponent | |||||
} | |||||
}, | |||||
{ | |||||
statePlugins: { | |||||
example: { | |||||
selectors: { | |||||
foo() { return "and this came from the system" } | |||||
} | |||||
} | |||||
} | |||||
} | |||||
] | |||||
}) | |||||
// When | |||||
var Component = system.getSystem().getComponent("ContainerComponent", true) | |||||
const renderedComponent = render( | |||||
<Provider store={system.getStore()}> | |||||
<Component fromOwnProps="and this came from my own props" /> | |||||
</Provider> | |||||
) | |||||
// Then | |||||
expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props") | |||||
}) | |||||
}) | |||||
}) | }) |