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 } }