From c0cfaabd7e7492c54211015250adf98bf8bc5601 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sat, 19 Aug 2017 08:32:21 -0600 Subject: [PATCH 01/14] Remove unused `getComponent` as prop to Date: Sat, 19 Aug 2017 08:33:03 -0600 Subject: [PATCH 02/14] Move performance debugging tools to app.jsx --- src/core/components/app.jsx | 15 ++++++++++++++- src/core/index.js | 5 ----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/core/components/app.jsx b/src/core/components/app.jsx index 9ef5a8fd..e701ba06 100644 --- a/src/core/components/app.jsx +++ b/src/core/components/app.jsx @@ -1,6 +1,16 @@ import React from "react" import PropTypes from "prop-types" +let Perf = null +let ReactPerfTool = null +if (process.env.NODE_ENV !== "production") { + Perf = require("react-addons-perf") + window.Perf = Perf + + ReactPerfTool = require("react-perf-tool") + require("react-perf-tool/lib/styles.css") +} + export default class App extends React.Component { getLayout() { @@ -14,7 +24,10 @@ export default class App extends React.Component { const Layout = this.getLayout() return ( - +
+ + +
) } } diff --git a/src/core/index.js b/src/core/index.js index 9d9c0ac3..3dbcede4 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -6,11 +6,6 @@ import ApisPreset from "core/presets/apis" import * as AllPlugins from "core/plugins/all" import { parseSearch } from "core/utils" -if (process.env.NODE_ENV !== "production") { - const Perf = require("react-addons-perf") - window.Perf = Perf -} - // eslint-disable-next-line no-undef const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo From ff2ed2584ed498cb4ae0c340f41bee56f58ce296 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sat, 19 Aug 2017 13:59:09 -0600 Subject: [PATCH 03/14] Revert Perf tool back to core/index.js --- src/core/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/index.js b/src/core/index.js index 3dbcede4..9f9e4c17 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -6,6 +6,10 @@ import ApisPreset from "core/presets/apis" import * as AllPlugins from "core/plugins/all" import { parseSearch } from "core/utils" +if (process.env.NODE_ENV !== "production") { + window.Perf = require("react-addons-perf") +} + // eslint-disable-next-line no-undef const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo From 0b41c917d133fbe3eb58c28b532f686833496333 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sat, 19 Aug 2017 13:59:24 -0600 Subject: [PATCH 04/14] Revert Perf tool back to core/index.js --- src/core/components/app.jsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/core/components/app.jsx b/src/core/components/app.jsx index e701ba06..7ff4662f 100644 --- a/src/core/components/app.jsx +++ b/src/core/components/app.jsx @@ -1,16 +1,6 @@ import React from "react" import PropTypes from "prop-types" -let Perf = null -let ReactPerfTool = null -if (process.env.NODE_ENV !== "production") { - Perf = require("react-addons-perf") - window.Perf = Perf - - ReactPerfTool = require("react-perf-tool") - require("react-perf-tool/lib/styles.css") -} - export default class App extends React.Component { getLayout() { @@ -26,7 +16,6 @@ export default class App extends React.Component { return (
-
) } From d4d66b80ca90bd5941eee55883489a22e82cf5a7 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 07:55:54 -0600 Subject: [PATCH 05/14] Add OperationContainer component --- src/core/containers/OperationContainer.jsx | 210 +++++++++++++++++++++ src/core/presets/base.js | 5 +- 2 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/core/containers/OperationContainer.jsx diff --git a/src/core/containers/OperationContainer.jsx b/src/core/containers/OperationContainer.jsx new file mode 100644 index 00000000..139fe2e3 --- /dev/null +++ b/src/core/containers/OperationContainer.jsx @@ -0,0 +1,210 @@ +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 Operation 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, + isShownKey: PropTypes.instanceOf(Iterable).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, + 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 + } + + static mapStateToProps(nextState, props) { + const { layoutSelectors, getConfigs } = props + const { docExpansion, deepLinking } = getConfigs() + const op = props.op + const path = op.get("path", "") + const method = op.get("method", "") + const operationId = op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id") + const isShownKey = fromJS(["operations", props.tag, operationId]) + const isDeepLinkingEnabled = deepLinking && deepLinking !== "false" + + return { + path, + method, + operationId, + isDeepLinkingEnabled, + isShown: layoutSelectors.isShown(isShownKey, docExpansion === "full" ), + jumpToKey: `paths.${path}.${method}`, + isShownKey: isShownKey, + allowTryItOut: props.specSelectors.allowTryItOutFor(op.get("path"), op.get("method")), + response: props.specSelectors.responseFor(op.get("path"), op.get("method")), + request: props.specSelectors.requestFor(op.get("path"), op.get("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) + } + } + + shouldComponentUpdate(nextProps, nextState) { + return this.state.tryItOutEnabled !== nextState.tryItOutEnabled + || this.state.executeInProgress !== nextState.executeInProgress + || this.props.op !== nextProps.op + || this.props.tag !== nextProps.tag + || this.props.path !== nextProps.path + || this.props.method !== nextProps.method + || this.props.operationId !== nextProps.operationId + || this.props.showSummary !== nextProps.showSummary + || this.props.isShown !== nextProps.isShown + || this.props.isShownKey !== nextProps.isShownKey + || this.props.jumpToKey !== nextProps.jumpToKey + || this.props.allowTryItOut !== nextProps.allowTryItOut + || this.props.displayOperationId !== nextProps.displayOperationId + || this.props.displayRequestDuration !== nextProps.displayRequestDuration + || this.props.response !== nextProps.response + || this.props.request !== nextProps.request + || this.props.isDeepLinkingEnabled !== nextProps.isDeepLinkingEnabled + } + + toggleShown =() => { + let { layoutActions, isShownKey, isShown } = this.props + 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 }) + } + + render() { + let { + op, + tag, + path, + method, + operationId, + showSummary, + isShown, + isShownKey, + jumpToKey, + allowTryItOut, + response, + request, + displayOperationId, + displayRequestDuration, + isDeepLinkingEnabled, + specSelectors, + specActions, + getComponent, + layoutSelectors, + layoutActions, + authActions, + authSelectors, + fn + } = this.props + + const Operation = getComponent( "operation" ) + + const operationProps = fromJS({ + op, + tag, + path, + method, + operationId, + showSummary, + isShown, + isShownKey, + jumpToKey, + allowTryItOut, + response, + request, + displayOperationId, + displayRequestDuration, + isDeepLinkingEnabled, + executeInProgress: this.state.executeInProgress, + tryItOutEnabled: this.state.tryItOutEnabled + }) + + return ( + + ) + } + +} diff --git a/src/core/presets/base.js b/src/core/presets/base.js index 10a12645..c22f2255 100644 --- a/src/core/presets/base.js +++ b/src/core/presets/base.js @@ -12,6 +12,8 @@ import SplitPaneModePlugin from "core/plugins/split-pane-mode" import downloadUrlPlugin from "core/plugins/download-url" import deepLinkingPlugin from "core/plugins/deep-linking" +import OperationContainer from "core/containers/OperationContainer" + import App from "core/components/app" import AuthorizationPopup from "core/components/auth/authorization-popup" import AuthorizeBtn from "core/components/auth/authorize-btn" @@ -107,7 +109,8 @@ export default function() { TryItOutButton, Markdown, BaseLayout, - VersionStamp + VersionStamp, + OperationContainer } } From dd414534f907c208b7634ffa67d62383e1ff3ce3 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 07:56:40 -0600 Subject: [PATCH 06/14] Update Operation component to be dumb, update responses to accept Immutable prop types --- src/core/components/operation.jsx | 161 ++++++++++-------------------- src/core/components/responses.jsx | 10 +- 2 files changed, 57 insertions(+), 114 deletions(-) diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index 4f6534db..1790d6a3 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -1,27 +1,16 @@ import React, { PureComponent } from "react" import PropTypes from "prop-types" import { getList } from "core/utils" -import * as CustomPropTypes from "core/proptypes" - -//import "less/opblock" +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, + operation: PropTypes.instanceOf(Iterable).isRequired, - isShownKey: CustomPropTypes.arrayOrString.isRequired, - jumpToKey: CustomPropTypes.arrayOrString.isRequired, - - 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, authActions: PropTypes.object, @@ -30,8 +19,7 @@ export default class Operation extends PureComponent { specSelectors: 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 = { @@ -42,94 +30,57 @@ export default class Operation extends PureComponent { 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 }) + shouldComponentUpdate(nextProps) { + return this.props.operation !== nextProps.operation } render() { let { - isShownKey, - jumpToKey, - path, - method, - operation, - showSummary, - response, - request, - allowTryItOut, - displayOperationId, - displayRequestDuration, + toggleShown, + onTryoutClick, + onCancelClick, + onExecute, fn, getComponent, specActions, specSelectors, authActions, - authSelectors, - getConfigs + authSelectors } = 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, + isShownKey, + jumpToKey, + path, + method, + op, + showSummary, + operationId, + allowTryItOut, + displayOperationId, + displayRequestDuration, + isDeepLinkingEnabled, + tryItOutEnabled, + executeInProgress + } = operationProps.toJS() + let response = operationProps.get("response") + let request = operationProps.get("request") + + let { + summary, + description, + deprecated, + externalDocs, + schemes + } = op.operation + + let operation = operationProps.getIn(["op", "operation"]) let responses = operation.get("responses") - let security = operation.get("security") || specSelectors.security() let produces = operation.get("produces") - let schemes = operation.get("schemes") + let security = operation.get("security") || specSelectors.security() let parameters = getList(operation, ["parameters"]) - let operationId = operation.get("__originalOperationId") let operationScheme = specSelectors.operationScheme(path, method) const Responses = getComponent("responses") @@ -142,23 +93,17 @@ export default class Operation extends PureComponent { const Markdown = getComponent( "Markdown" ) const Schemes = getComponent( "schemes" ) - const { deepLinking } = getConfigs() - - const isDeepLinkingEnabled = deepLinking && deepLinking !== "false" - // Merge in Live Response - if(response && response.size > 0) { + if(responses && response && response.size > 0) { let notDocumented = !responses.get(String(response.get("status"))) 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 ( -
-
+
+
{method.toUpperCase()} - +
{ deprecated &&

Warning: Deprecated

} { description && @@ -212,8 +157,8 @@ export default class Operation extends PureComponent { parameters={parameters} operation={operation} onChangeKey={onChangeKey} - onTryoutClick = { this.onTryoutClick } - onCancelClick = { this.onCancelClick } + onTryoutClick = { onTryoutClick } + onCancelClick = { onCancelClick } tryItOutEnabled = { tryItOutEnabled } allowTryItOut={allowTryItOut} @@ -237,25 +182,23 @@ export default class Operation extends PureComponent { { !tryItOutEnabled || !allowTryItOut ? null : + onExecute={ onExecute } /> } { (!tryItOutEnabled || !response || !allowTryItOut) ? null : }
- {this.state.executeInProgress ?
: null} + {executeInProgress ?
: null} { !responses ? null : Date: Sun, 20 Aug 2017 07:57:07 -0600 Subject: [PATCH 07/14] Update Operations component to call OperationContainer instead of Operation.jsx --- src/core/components/operations.jsx | 33 ++++-------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index ef1d4248..724c82f9 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -1,8 +1,5 @@ import React from "react" import PropTypes from "prop-types" -import { helpers } from "swagger-client" - -const { opId } = helpers export default class Operations extends React.Component { @@ -32,7 +29,7 @@ export default class Operations extends React.Component { let taggedOps = specSelectors.taggedOperations() - const Operation = getComponent("operation") + const Operation = getComponent("OperationContainer", true) const Collapse = getComponent("Collapse") let showSummary = layoutSelectors.showSummary() @@ -117,42 +114,20 @@ export default class Operations extends React.Component { { 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 isShownKey = ["operations", tag, 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 Date: Sun, 20 Aug 2017 08:06:59 -0600 Subject: [PATCH 08/14] Remove unnecessary div in app.jsx --- src/core/components/app.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/components/app.jsx b/src/core/components/app.jsx index 7ff4662f..9ef5a8fd 100644 --- a/src/core/components/app.jsx +++ b/src/core/components/app.jsx @@ -14,9 +14,7 @@ export default class App extends React.Component { const Layout = this.getLayout() return ( -
- -
+ ) } } From 8426dcdf7b10c2f428c3cdb152beb5d0417b1906 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 08:16:02 -0600 Subject: [PATCH 09/14] Fix failed test due to removed `getConfigs` --- src/core/components/operation.jsx | 2 ++ src/core/containers/OperationContainer.jsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index 78a9c3fe..d2386521 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -13,6 +13,7 @@ export default class Operation extends PureComponent { onExecute: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired, authActions: PropTypes.object, authSelectors: PropTypes.object, specActions: PropTypes.object.isRequired, @@ -42,6 +43,7 @@ export default class Operation extends PureComponent { onExecute, fn, getComponent, + getConfigs, specActions, specSelectors, authActions, diff --git a/src/core/containers/OperationContainer.jsx b/src/core/containers/OperationContainer.jsx index 139fe2e3..103bdcfd 100644 --- a/src/core/containers/OperationContainer.jsx +++ b/src/core/containers/OperationContainer.jsx @@ -157,6 +157,7 @@ export default class Operation extends PureComponent { specSelectors, specActions, getComponent, + getConfigs, layoutSelectors, layoutActions, authActions, @@ -202,6 +203,7 @@ export default class Operation extends PureComponent { authActions={ authActions } authSelectors={ authSelectors } getComponent={ getComponent } + getConfigs={ getConfigs } fn={fn} /> ) From bcefb6eb3e00d857ab122d8c77ff8537286cbe0b Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 15:25:13 -0600 Subject: [PATCH 10/14] Convert `pathMethod` prop to two separate props. --- src/core/components/live-response.jsx | 7 ++++--- src/core/components/operation.jsx | 3 ++- src/core/components/responses.jsx | 28 ++++++++++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/core/components/live-response.jsx b/src/core/components/live-response.jsx index e9e3fa2d..457e3306 100644 --- a/src/core/components/live-response.jsx +++ b/src/core/components/live-response.jsx @@ -30,17 +30,18 @@ export default class LiveResponse extends React.Component { static propTypes = { response: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired, - pathMethod: PropTypes.object.isRequired, + path: PropTypes.string.isRequired, + method: PropTypes.string.isRequired, getComponent: PropTypes.func.isRequired, displayRequestDuration: PropTypes.bool.isRequired, getConfigs: PropTypes.func.isRequired } 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() diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index d2386521..680d2701 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -213,7 +213,8 @@ export default class Operation extends PureComponent { specActions={ specActions } produces={ produces } producesValue={ operation.get("produces_value") } - pathMethod={ [path, method] } + path={ path } + method={ method } displayRequestDuration={ displayRequestDuration } fn={fn} /> } diff --git a/src/core/components/responses.jsx b/src/core/components/responses.jsx index f37fa8b8..46c82a69 100644 --- a/src/core/components/responses.jsx +++ b/src/core/components/responses.jsx @@ -4,18 +4,18 @@ import { fromJS, Iterable } from "immutable" import { defaultStatusCode } from "core/utils" export default class Responses extends React.Component { - static propTypes = { request: PropTypes.instanceOf(Iterable), 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, specSelectors: PropTypes.object.isRequired, specActions: PropTypes.object.isRequired, - pathMethod: PropTypes.array.isRequired, - displayRequestDuration: PropTypes.bool.isRequired, fn: PropTypes.object.isRequired, getConfigs: PropTypes.func.isRequired } @@ -27,9 +27,26 @@ export default class Responses extends React.Component { displayRequestDuration: false } - onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val) + shouldComponentUpdate(nextProps) { + console.log("Responses SCU", this.props.tryItOutResponse.toJS(), nextProps.tryItOutResponse.toJS()) + let render = this.props.request !== nextProps.request + || 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 + + console.log("render", render) + + return render + } + + onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val) render() { + console.log("Responses render") let { responses, request, tryItOutResponse, getComponent, getConfigs, specSelectors, fn, producesValue, displayRequestDuration } = this.props let defaultCode = defaultStatusCode( responses ) @@ -60,7 +77,8 @@ export default class Responses extends React.Component { getComponent={ getComponent } getConfigs={ getConfigs } specSelectors={ specSelectors } - pathMethod={ this.props.pathMethod } + path={ this.props.path } + method={ this.props.method } displayRequestDuration={ displayRequestDuration } />

Responses

From 050f4d1918ab9ec4c34d7b48672ce3b440ce7036 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 17:02:51 -0600 Subject: [PATCH 11/14] Clean up OperationContainer props. --- src/core/components/operations.jsx | 17 ++++++------- src/core/containers/OperationContainer.jsx | 29 +++++++++++----------- src/core/plugins/view/root-injects.js | 2 +- src/core/system.js | 3 +-- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index 724c82f9..382960b7 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -29,14 +29,11 @@ export default class Operations extends React.Component { let taggedOps = specSelectors.taggedOperations() - const Operation = getComponent("OperationContainer", true) + const OperationContainer = getComponent("OperationContainer", true) const Collapse = getComponent("Collapse") - let showSummary = layoutSelectors.showSummary() let { docExpansion, - displayOperationId, - displayRequestDuration, maxDisplayedTags, deepLinking } = getConfigs() @@ -114,13 +111,15 @@ export default class Operations extends React.Component { { operations.map( op => { - return class extends Component { } const makeContainer = (getSystem, component, reduxStore) => { - const mapStateToProps = component.prototype.constructor.mapStateToProps || function(state) { + const mapStateToProps = component.prototype.mapStateToProps || function(state) { return {state} } let wrappedWithSystem = SystemWrapper(getSystem, component, reduxStore) diff --git a/src/core/system.js b/src/core/system.js index e4eee5b8..06071bc9 100644 --- a/src/core/system.js +++ b/src/core/system.js @@ -289,8 +289,7 @@ export default class Store { getMapStateToProps() { return () => { - let obj = Object.assign({}, this.getSystem()) - return obj + return Object.assign({}, this.getSystem()) } } From cfb4625eb08059ea40e662f2ff462a4b24f14f6e Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 20 Aug 2017 18:50:49 -0600 Subject: [PATCH 12/14] Add `shouldComponentUpdate` to response.jsx and live-response.jsx. Remove `isShownKey` from `shouldComponentUpdate` of OperationContainer. Moved `response` and `request` out to separate props for operation.jsx. Removed unused `request` prop from responses.jsx. --- src/core/components/live-response.jsx | 17 +++++++++++++---- src/core/components/operation.jsx | 14 ++++++++------ src/core/components/response.jsx | 10 ++++++++-- src/core/components/responses.jsx | 16 ++++------------ src/core/containers/OperationContainer.jsx | 7 ++++--- 5 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/core/components/live-response.jsx b/src/core/components/live-response.jsx index 457e3306..4a581d4e 100644 --- a/src/core/components/live-response.jsx +++ b/src/core/components/live-response.jsx @@ -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,15 +29,24 @@ Duration.propTypes = { export default class LiveResponse extends React.Component { static propTypes = { - response: PropTypes.object.isRequired, - specSelectors: PropTypes.object.isRequired, + response: PropTypes.instanceOf(Iterable).isRequired, path: PropTypes.string.isRequired, method: PropTypes.string.isRequired, - getComponent: PropTypes.func.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, path, method } = this.props const { showMutatedRequest } = getConfigs() @@ -112,7 +122,6 @@ export default class LiveResponse extends React.Component { static propTypes = { getComponent: PropTypes.func.isRequired, - request: ImPropTypes.map, response: ImPropTypes.map } } diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index 680d2701..7e97d5d8 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -6,6 +6,8 @@ import { Iterable } from "immutable" export default class Operation extends PureComponent { static propTypes = { operation: PropTypes.instanceOf(Iterable).isRequired, + response: PropTypes.instanceOf(Iterable), + request: PropTypes.instanceOf(Iterable), toggleShown: PropTypes.func.isRequired, onTryoutClick: PropTypes.func.isRequired, @@ -24,19 +26,21 @@ export default class Operation extends PureComponent { } static defaultProps = { - showSummary: true, + operation: null, response: null, - allowTryItOut: true, - displayOperationId: false, - displayRequestDuration: false + request: null } shouldComponentUpdate(nextProps) { return this.props.operation !== nextProps.operation + || this.props.response !== nextProps.response + || this.props.request !== nextProps.request } render() { let { + response, + request, toggleShown, onTryoutClick, onCancelClick, @@ -67,8 +71,6 @@ export default class Operation extends PureComponent { tryItOutEnabled, executeInProgress } = operationProps.toJS() - let response = operationProps.get("response") - let request = operationProps.get("request") let { summary, diff --git a/src/core/components/response.jsx b/src/core/components/response.jsx index 8c0a8bf1..aca6e0d6 100644 --- a/src/core/components/response.jsx +++ b/src/core/components/response.jsx @@ -1,6 +1,6 @@ import React from "react" import PropTypes from "prop-types" -import { fromJS, Seq } from "immutable" +import { fromJS, Seq, Iterable } from "immutable" import { getSampleSchema } from "core/utils" const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => { @@ -41,7 +41,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, specSelectors: PropTypes.object.isRequired, @@ -53,6 +53,12 @@ export default class Response extends React.Component { response: fromJS({}), }; + shouldComponentUpdate(nextProps) { + return this.props.code !== nextProps.code + || this.props.response !== nextProps.response + || this.props.className !== nextProps.className + } + render() { let { code, diff --git a/src/core/components/responses.jsx b/src/core/components/responses.jsx index 46c82a69..0525fac8 100644 --- a/src/core/components/responses.jsx +++ b/src/core/components/responses.jsx @@ -5,7 +5,6 @@ import { defaultStatusCode } from "core/utils" export default class Responses extends React.Component { static propTypes = { - request: PropTypes.instanceOf(Iterable), tryItOutResponse: PropTypes.instanceOf(Iterable), responses: PropTypes.instanceOf(Iterable).isRequired, produces: PropTypes.instanceOf(Iterable), @@ -21,33 +20,27 @@ export default class Responses extends React.Component { } static defaultProps = { - request: null, tryItOutResponse: null, produces: fromJS(["application/json"]), displayRequestDuration: false } shouldComponentUpdate(nextProps) { - console.log("Responses SCU", this.props.tryItOutResponse.toJS(), nextProps.tryItOutResponse.toJS()) - let render = this.props.request !== nextProps.request - || this.props.tryItOutResponse !== nextProps.tryItOutResponse + // 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 - - console.log("render", render) - return render } onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val) render() { - console.log("Responses render") - let { responses, request, tryItOutResponse, getComponent, getConfigs, specSelectors, fn, producesValue, displayRequestDuration } = this.props + let { responses, tryItOutResponse, getComponent, getConfigs, specSelectors, fn, producesValue, displayRequestDuration } = this.props let defaultCode = defaultStatusCode( responses ) const ContentType = getComponent( "contentType" ) @@ -72,8 +65,7 @@ export default class Responses extends React.Component { { !tryItOutResponse ? null :
- { @@ -177,7 +177,6 @@ export default class OperationContainer extends PureComponent { isShownKey, jumpToKey, allowTryItOut, - response, request, displayOperationId, displayRequestDuration, @@ -189,6 +188,8 @@ export default class OperationContainer extends PureComponent { return ( Date: Sun, 20 Aug 2017 18:57:59 -0600 Subject: [PATCH 13/14] Fixed mapStateToProps test to handle non-static mapStateToProps --- test/core/system/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/system/system.js b/test/core/system/system.js index 67447276..2b4990df 100644 --- a/test/core/system/system.js +++ b/test/core/system/system.js @@ -470,7 +470,7 @@ describe("bound system", function(){ it("allows container components to provide their own `mapStateToProps` function", function() { // Given class ContainerComponent extends PureComponent { - static mapStateToProps(nextState, props) { + mapStateToProps(nextState, props) { return { "abc": "This came from mapStateToProps" } From 6f98fa9f3b03ea05a834cf9a71d615c9adcf5d1e Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Fri, 15 Sep 2017 22:31:02 -0600 Subject: [PATCH 14/14] Fixes after merge with ft/3584 branch --- src/core/components/responses.jsx | 10 +++++----- src/core/plugins/oas3/actions.js | 4 ++-- src/core/plugins/oas3/reducers.js | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/core/components/responses.jsx b/src/core/components/responses.jsx index 63708b2d..832201b4 100644 --- a/src/core/components/responses.jsx +++ b/src/core/components/responses.jsx @@ -15,7 +15,7 @@ export default class Responses extends React.Component { getComponent: PropTypes.func.isRequired, specSelectors: PropTypes.object.isRequired, specActions: PropTypes.object.isRequired, - oas3Actions: PropTypes.object.isRequired, + oas3Actions: PropTypes.object.isRequired, fn: PropTypes.object.isRequired, getConfigs: PropTypes.func.isRequired } @@ -38,14 +38,15 @@ export default class Responses extends React.Component { return render } - onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val) + 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 }) } } @@ -53,7 +54,6 @@ export default class Responses extends React.Component { render() { let { responses, - request, tryItOutResponse, getComponent, getConfigs, diff --git a/src/core/plugins/oas3/actions.js b/src/core/plugins/oas3/actions.js index ad81f3e7..c9abc855 100644 --- a/src/core/plugins/oas3/actions.js +++ b/src/core/plugins/oas3/actions.js @@ -28,10 +28,10 @@ export function setRequestContentType ({ value, pathMethod }) { } } -export function setResponseContentType ({ value, pathMethod }) { +export function setResponseContentType ({ value, path, method }) { return { type: UPDATE_RESPONSE_CONTENT_TYPE, - payload: { value, pathMethod } + payload: { value, path, method } } } diff --git a/src/core/plugins/oas3/reducers.js b/src/core/plugins/oas3/reducers.js index 149f55e3..8590284d 100644 --- a/src/core/plugins/oas3/reducers.js +++ b/src/core/plugins/oas3/reducers.js @@ -18,8 +18,7 @@ export default { let [path, method] = pathMethod 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) }, [UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{