diff --git a/README.md b/README.md index 57bb312c..97138956 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ deepLinking | If set to `true`, enables dynamic deep linking for tags and operat requestInterceptor | MUST be a function. Function to intercept try-it-out requests. Accepts one argument requestInterceptor(request) and must return the potentially modified request. responseInterceptor | MUST be a function. Function to intercept try-it-out responses. Accepts one argument responseInterceptor(response) and must return the potentially modified response. showMutatedRequest | If set to `true` (the default), uses the mutated request returned from a rquestInterceptor to produce the curl command in the UI, otherwise the request before the requestInterceptor was applied is used. +showExtensions | Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema. The default is `false`. ### Plugins diff --git a/src/core/components/array-model.jsx b/src/core/components/array-model.jsx index a68a3562..6f646bb6 100644 --- a/src/core/components/array-model.jsx +++ b/src/core/components/array-model.jsx @@ -7,6 +7,7 @@ export default class ArrayModel extends Component { static propTypes = { schema: PropTypes.object.isRequired, getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired, specSelectors: PropTypes.object.isRequired, name: PropTypes.string, required: PropTypes.bool, @@ -15,7 +16,7 @@ export default class ArrayModel extends Component { } render(){ - let { getComponent, schema, depth, expandDepth, name } = this.props + let { getComponent, getConfigs, schema, depth, expandDepth, name } = this.props let description = schema.get("description") let items = schema.get("items") let title = schema.get("title") || name @@ -46,7 +47,7 @@ export default class ArrayModel extends Component { !description ? null : } - + ] diff --git a/src/core/components/auth/oauth2.jsx b/src/core/components/auth/oauth2.jsx index e6dbe6a5..fa980bac 100644 --- a/src/core/components/auth/oauth2.jsx +++ b/src/core/components/auth/oauth2.jsx @@ -200,11 +200,11 @@ export default class Oauth2 extends React.Component {
-
+ } diff --git a/src/core/components/operation-extension-row.jsx b/src/core/components/operation-extension-row.jsx new file mode 100644 index 00000000..7c3a90dc --- /dev/null +++ b/src/core/components/operation-extension-row.jsx @@ -0,0 +1,15 @@ +import React from "react" +import PropTypes from "prop-types" + +export const OperationExtRow = ({ xKey, xVal }) => { + return ( + { xKey } + { String(xVal) } + ) +} +OperationExtRow.propTypes = { + xKey: PropTypes.string, + xVal: PropTypes.any +} + +export default OperationExtRow diff --git a/src/core/components/operation-extensions.jsx b/src/core/components/operation-extensions.jsx new file mode 100644 index 00000000..256f7a52 --- /dev/null +++ b/src/core/components/operation-extensions.jsx @@ -0,0 +1,35 @@ +import React from "react" +import PropTypes from "prop-types" + +export const OperationExt = ({ extensions, getComponent }) => { + let OperationExtRow = getComponent("OperationExtRow") + return ( +
+
+

Extensions

+
+
+ + + + + + + + + + { + extensions.entrySeq().map(([k, v]) => ) + } + +
FieldValue
+
+
+ ) +} +OperationExt.propTypes = { + extensions: PropTypes.object.isRequired, + getComponent: PropTypes.func.isRequired +} + +export default OperationExt diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index df9eb7c6..8d4a2683 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -1,7 +1,7 @@ import React, { PureComponent } from "react" import PropTypes from "prop-types" import { getList } from "core/utils" -import { sanitizeUrl } from "core/utils" +import { getExtensions, sanitizeUrl } from "core/utils" import { Iterable } from "immutable" export default class Operation extends PureComponent { @@ -85,6 +85,7 @@ export default class Operation extends PureComponent { let parameters = getList(operation, ["parameters"]) let operationScheme = specSelectors.operationScheme(path, method) let isShownKey = ["operations", tag, operationId] + let extensions = getExtensions(operation) const Responses = getComponent("responses") const Parameters = getComponent( "parameters" ) @@ -95,6 +96,9 @@ export default class Operation extends PureComponent { const Collapse = getComponent( "Collapse" ) const Markdown = getComponent( "Markdown" ) const Schemes = getComponent( "schemes" ) + const OperationExt = getComponent( "OperationExt" ) + + const { showExtensions } = getConfigs() // Merge in Live Response if(responses && response && response.size > 0) { @@ -149,17 +153,18 @@ export default class Operation extends PureComponent { } { - externalDocs && externalDocs.get("url") ? + externalDocs && externalDocs.url ?

Find more details

- + - { externalDocs.get("url") } + { externalDocs.url }
: null } + } + + { !showExtensions || !extensions.size ? null : + + } diff --git a/src/core/components/parameter-extension.jsx b/src/core/components/parameter-extension.jsx new file mode 100644 index 00000000..cf1c116f --- /dev/null +++ b/src/core/components/parameter-extension.jsx @@ -0,0 +1,12 @@ +import React from "react" +import PropTypes from "prop-types" + +export const ParameterExt = ({ xKey, xVal }) => { + return
{ xKey }: { String(xVal) }
+} +ParameterExt.propTypes = { + xKey: PropTypes.string, + xVal: PropTypes.any +} + +export default ParameterExt diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx index 71a2765a..c286ef71 100644 --- a/src/core/components/parameter-row.jsx +++ b/src/core/components/parameter-row.jsx @@ -2,6 +2,7 @@ import React, { Component } from "react" import { Map } from "immutable" import PropTypes from "prop-types" import win from "core/window" +import { getExtensions } from "core/utils" export default class ParameterRow extends Component { static propTypes = { @@ -72,6 +73,8 @@ export default class ParameterRow extends Component { let { isOAS3 } = specSelectors + const { showExtensions } = getConfigs() + // const onChangeWrapper = (value) => onChange(param, value) const JsonSchemaForm = getComponent("JsonSchemaForm") const ParamBody = getComponent("ParamBody") @@ -91,6 +94,7 @@ export default class ParameterRow extends Component { const ModelExample = getComponent("modelExample") const Markdown = getComponent("Markdown") + const ParameterExt = getComponent("ParameterExt") let schema = param.get("schema") let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type") @@ -100,6 +104,7 @@ export default class ParameterRow extends Component { let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"]) let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) let value = parameter ? parameter.get("value") : "" + let extensions = getExtensions(param) return ( @@ -113,6 +118,7 @@ export default class ParameterRow extends Component { { isOAS3 && isOAS3() && param.get("deprecated") ? "deprecated": null }
({ param.get("in") })
+ { !showExtensions || !extensions.size ? null : extensions.map((v, key) => )} diff --git a/src/core/components/primitive-model.jsx b/src/core/components/primitive-model.jsx index c14413a9..1d49d7d4 100644 --- a/src/core/components/primitive-model.jsx +++ b/src/core/components/primitive-model.jsx @@ -1,5 +1,6 @@ import React, { Component } from "react" import PropTypes from "prop-types" +import { getExtensions } from "core/utils" const propStyle = { color: "#999", fontStyle: "italic" } @@ -7,12 +8,15 @@ export default class Primitive extends Component { static propTypes = { schema: PropTypes.object.isRequired, getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired, name: PropTypes.string, depth: PropTypes.number } render(){ - let { schema, getComponent, name, depth } = this.props + let { schema, getComponent, getConfigs, name, depth } = this.props + + const { showExtensions } = getConfigs() if(!schema || !schema.get) { // don't render if schema isn't correctly formed @@ -25,7 +29,10 @@ export default class Primitive extends Component { let enumArray = schema.get("enum") let title = schema.get("title") || name let description = schema.get("description") - let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 ) + let extensions = getExtensions(schema) + let properties = schema + .filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 ) + .filterNot( (v, key) => extensions.has(key) ) const Markdown = getComponent("Markdown") const EnumModel = getComponent("EnumModel") const Property = getComponent("Property") @@ -38,6 +45,9 @@ export default class Primitive extends Component { { properties.size ? properties.entrySeq().map( ( [ key, v ] ) => ) : null } + { + showExtensions && extensions.size ? extensions.entrySeq().map( ( [ key, v ] ) => ) : null + } { !description ? null : diff --git a/src/core/index.js b/src/core/index.js index 7298043a..14c0637f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -46,6 +46,7 @@ module.exports = function SwaggerUI(opts) { showMutatedRequest: true, defaultModelRendering: "example", defaultModelExpandDepth: 1, + showExtensions: false, // Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance. // Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest. diff --git a/src/core/plugins/oas3/wrap-components/model.jsx b/src/core/plugins/oas3/wrap-components/model.jsx index ab554534..ad1fa366 100644 --- a/src/core/plugins/oas3/wrap-components/model.jsx +++ b/src/core/plugins/oas3/wrap-components/model.jsx @@ -8,12 +8,13 @@ class ModelComponent extends Component { schema: PropTypes.object.isRequired, name: PropTypes.string, getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired, specSelectors: PropTypes.object.isRequired, expandDepth: PropTypes.number } render(){ - let { schema } = this.props + let { getConfigs, schema } = this.props let classes = ["model-box"] let isDeprecated = schema.get("deprecated") === true let message = null @@ -26,6 +27,7 @@ class ModelComponent extends Component { return
{message} diff --git a/src/core/presets/base.js b/src/core/presets/base.js index d608b544..133df134 100644 --- a/src/core/presets/base.js +++ b/src/core/presets/base.js @@ -30,11 +30,14 @@ import LiveResponse from "core/components/live-response" import OnlineValidatorBadge from "core/components/online-validator-badge" import Operations from "core/components/operations" import Operation from "core/components/operation" +import OperationExt from "core/components/operation-extensions" +import OperationExtRow from "core/components/operation-extension-row" import HighlightCode from "core/components/highlight-code" import Responses from "core/components/responses" import Response from "core/components/response" import ResponseBody from "core/components/response-body" import Parameters from "core/components/parameters" +import ParameterExt from "core/components/parameter-extension" import ParameterRow from "core/components/parameter-row" import Execute from "core/components/execute" import Headers from "core/components/headers" @@ -115,6 +118,9 @@ export default function() { Markdown, BaseLayout, VersionStamp, + OperationExt, + OperationExtRow, + ParameterExt, OperationContainer } } diff --git a/src/core/utils.js b/src/core/utils.js index 8babdbd8..70dd3cfe 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -692,3 +692,5 @@ export function getAcceptControllingResponse(responses) { export const createDeepLinkPath = (str) => typeof str == "string" || str instanceof String ? str.trim().replace(/\s/g, "_") : "" export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) ) + +export const getExtensions = (defObj) => defObj.filter((v, k) => /^x-/.test(k)) diff --git a/src/style/_table.scss b/src/style/_table.scss index 02dd92ba..3cbcc81f 100644 --- a/src/style/_table.scss +++ b/src/style/_table.scss @@ -131,7 +131,8 @@ table } } -.parameter__in +.parameter__in, +.parameter__extension { font-size: 12px; font-style: italic; diff --git a/test/components/primitive-model.js b/test/components/primitive-model.js index 9394bb8c..4b09b5af 100644 --- a/test/components/primitive-model.js +++ b/test/components/primitive-model.js @@ -14,6 +14,9 @@ describe("", function() { } const props = { getComponent: c => components[c], + getConfigs: () => ({ + showExtensions: false + }), name: "Name from props", depth: 1, schema: fromJS({ @@ -46,4 +49,4 @@ describe("", function() { }) }) -} ) \ No newline at end of file +} )