response.jsx 8.4 KB
Newer Older
R
RVKen 已提交
1 2
import React from "react"
import PropTypes from "prop-types"
3
import ImPropTypes from "react-immutable-proptypes"
4
import cx from "classnames"
K
kyle 已提交
5 6
import { fromJS, Seq, Iterable, List, Map } from "immutable"
import { getSampleSchema, fromJSOrdered, stringify } from "core/utils"
R
Ron 已提交
7

8
const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => {
9 10 11 12
  if (
    sampleResponse !== undefined &&
    sampleResponse !== null
  ) { return <div>
13
      <HighlightCode className="example" getConfigs={ getConfigs } value={ stringify(sampleResponse) } />
R
Ron 已提交
14 15 16 17 18 19
    </div>
  }
  return null
}

export default class Response extends React.Component {
20 21 22 23
  constructor(props, context) {
    super(props, context)

    this.state = {
24
      responseContentType: "",
25 26
    }
  }
R
Ron 已提交
27 28

  static propTypes = {
29 30
    path: PropTypes.string.isRequired,
    method: PropTypes.string.isRequired,
R
Ron 已提交
31
    code: PropTypes.string.isRequired,
32
    response: PropTypes.instanceOf(Iterable),
R
Ron 已提交
33 34
    className: PropTypes.string,
    getComponent: PropTypes.func.isRequired,
35
    getConfigs: PropTypes.func.isRequired,
R
Ron 已提交
36
    specSelectors: PropTypes.object.isRequired,
37
    oas3Actions: PropTypes.object.isRequired,
38
    specPath: ImPropTypes.list.isRequired,
R
Ron 已提交
39
    fn: PropTypes.object.isRequired,
40
    contentType: PropTypes.string,
41
    activeExamplesKey: PropTypes.string,
42 43
    controlsAcceptHeader: PropTypes.bool,
    onContentTypeChange: PropTypes.func
R
Ron 已提交
44 45 46 47
  }

  static defaultProps = {
    response: fromJS({}),
48
    onContentTypeChange: () => {}
R
Ron 已提交
49 50
  };

51 52 53 54 55 56 57 58 59
  _onContentTypeChange = (value) => {
    const { onContentTypeChange, controlsAcceptHeader } = this.props
    this.setState({ responseContentType: value })
    onContentTypeChange({
      value: value,
      controlsAcceptHeader
    })
  }

60 61 62 63 64 65 66 67 68 69 70
  getTargetExamplesKey = () => {
    const { response, contentType, activeExamplesKey } = this.props

    const activeContentType = this.state.responseContentType || contentType
    const activeMediaType = response.getIn(["content", activeContentType], Map({}))
    const examplesForMediaType = activeMediaType.get("examples", null)

    const firstExamplesKey = examplesForMediaType.keySeq().first()
    return activeExamplesKey || firstExamplesKey
  }

R
Ron 已提交
71 72
  render() {
    let {
73 74
      path,
      method,
R
Ron 已提交
75 76 77
      code,
      response,
      className,
J
Josh Ponelat 已提交
78
      specPath,
R
Ron 已提交
79 80
      fn,
      getComponent,
81
      getConfigs,
R
Ron 已提交
82
      specSelectors,
83
      contentType,
84 85
      controlsAcceptHeader,
      oas3Actions,
R
Ron 已提交
86 87 88
    } = this.props

    let { inferSchema } = fn
89
    let isOAS3 = specSelectors.isOAS3()
R
Ron 已提交
90 91

    let headers = response.get("headers")
92
    let links = response.get("links")
R
Ron 已提交
93 94 95
    const Headers = getComponent("headers")
    const HighlightCode = getComponent("highlightCode")
    const ModelExample = getComponent("modelExample")
96
    const Markdown = getComponent("Markdown", true)
97
    const OperationLink = getComponent("operationLink")
98
    const ContentType = getComponent("contentType")
99 100 101
    const ExamplesSelect = getComponent("ExamplesSelect")
    const Example = getComponent("Example")

R
Ron 已提交
102

103
    var sampleResponse
J
Josh Ponelat 已提交
104
    var schema, specPathWithPossibleSchema
105

K
kyle 已提交
106
    const activeContentType = this.state.responseContentType || contentType
107 108
    const activeMediaType = response.getIn(["content", activeContentType], Map({}))
    const examplesForMediaType = activeMediaType.get("examples", null)
K
kyle 已提交
109

110 111
    // Goal: find a schema value for `schema`
    if(isOAS3) {
112
      const oas3SchemaForContentType = activeMediaType.get("schema")
113 114 115 116 117 118 119

      schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null
      specPathWithPossibleSchema = oas3SchemaForContentType ? List(["content", this.state.responseContentType, "schema"]) : specPath
    } else {
      schema = response.get("schema")
      specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
    }
K
kyle 已提交
120

121 122 123 124 125 126 127 128 129 130 131
    // Goal: find an example value for `sampleResponse`
    if(isOAS3) {
      const oas3SchemaForContentType = activeMediaType.get("schema", Map({}))

      if(examplesForMediaType) {
        const targetExamplesKey = this.getTargetExamplesKey()
        const targetExample = examplesForMediaType.get(targetExamplesKey, Map({}))
        sampleResponse = stringify(targetExample.get("value"))
      } else if(activeMediaType.get("example") !== undefined) {
        // use the example key's value
        sampleResponse = stringify(activeMediaType.get("example"))
K
kyle 已提交
132
      } else {
133 134
        // use an example value generated based on the schema
        sampleResponse = getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, {
K
kyle 已提交
135 136 137
          includeReadOnly: true
        })
      }
138
    } else {
139 140 141 142
      if(response.getIn(["examples", activeContentType])) {
        sampleResponse = response.getIn(["examples", activeContentType])
      } else {
        sampleResponse = schema ? getSampleSchema(
143 144
          schema.toJS(),
          activeContentType,
145 146 147 148 149 150
          {
            includeReadOnly: true,
            includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
          }
        ) : null
      }
151
    }
152

153
    let example = getExampleComponent( sampleResponse, HighlightCode, getConfigs )
R
Ron 已提交
154 155

    return (
K
kyle 已提交
156
      <tr className={ "response " + ( className || "") } data-code={code}>
157
        <td className="response-col_status">
R
Ron 已提交
158 159
          { code }
        </td>
160
        <td className="response-col_description">
R
Ron 已提交
161 162

          <div className="response-col_description__inner">
K
Kyle Shockey 已提交
163
            <Markdown source={ response.get( "description" ) } />
R
Ron 已提交
164 165
          </div>

166 167 168 169 170 171 172 173 174 175 176
          {isOAS3 && response.get("content") ? (
            <section className="response-controls">
              <div
                className={cx("response-control-media-type", {
                  "response-control-media-type--accept-controller": controlsAcceptHeader
                })}
              >
                <small className="response-control-media-type__title">
                  Media type
                </small>
                <ContentType
177
                  value={this.state.responseContentType}
178 179 180 181 182
                  contentTypes={
                    response.get("content")
                      ? response.get("content").keySeq()
                      : Seq()
                  }
183
                  onChange={this._onContentTypeChange}
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
                />
                {controlsAcceptHeader ? (
                  <small className="response-control-media-type__accept-message">
                    Controls <code>Accept</code> header.
                  </small>
                ) : null}
              </div>
              {examplesForMediaType ? (
                <div className="response-control-examples">
                  <small className="response-control-examples__title">
                    Examples
                  </small>
                  <ExamplesSelect
                    examples={examplesForMediaType}
                    currentExampleKey={this.getTargetExamplesKey()}
                    onSelect={key =>
                      oas3Actions.setActiveExamplesMember({
                        name: key,
                        pathMethod: [path, method],
                        contextType: "responses",
                        contextName: code
                      })
                    }
                    showLabels={false}
208
                  />
209 210 211 212
                </div>
              ) : null}
            </section>
          ) : null}
213

214
          { example || schema ? (
R
Ron 已提交
215
            <ModelExample
J
Josh Ponelat 已提交
216
              specPath={specPathWithPossibleSchema}
R
Ron 已提交
217
              getComponent={ getComponent }
218
              getConfigs={ getConfigs }
R
Ron 已提交
219
              specSelectors={ specSelectors }
220
              schema={ fromJSOrdered(schema) }
221 222
              example={ example }
              includeReadOnly={ true }/>
223 224 225 226 227 228
          ) : null }

          { isOAS3 && examplesForMediaType ? (
              <Example
                example={examplesForMediaType.get(this.getTargetExamplesKey(), Map({}))}
                getComponent={getComponent}
229
                getConfigs={getConfigs}
230 231
                omitValue={true}
              />
R
Ron 已提交
232 233 234
          ) : null}

          { headers ? (
235 236 237 238
            <Headers
              headers={ headers }
              getComponent={ getComponent }
            />
R
Ron 已提交
239 240
          ) : null}

241
        </td>
242
        {isOAS3 ? <td className="response-col_links">
243 244
          { links ?
            links.toSeq().map((link, key) => {
K
Kyle Shockey 已提交
245
              return <OperationLink key={key} name={key} link={ link } getComponent={getComponent}/>
246 247 248
            })
          : <i>No links</i>}
        </td> : null}
R
Ron 已提交
249 250 251 252
      </tr>
    )
  }
}