From 4fe27786f407a0c2b038a68dc1faf6ad966307bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 27 Jun 2017 15:29:07 +0200 Subject: [PATCH 01/25] Adding apisSorter options, taking a string or a function as a configuration value --- .gitignore | 1 + README.md | 6 ++- dev-helpers/index.html | 87 +++++++++++++++--------------- src/core/plugins/spec/selectors.js | 21 +++++--- src/core/utils.js | 5 +- 5 files changed, 67 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 36ccaaa9..2e9dcf9c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules npm-debug.log* .eslintcache package-lock.json +*.iml diff --git a/README.md b/README.md index eff32bc7..13567ca6 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,10 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout" + layout: "StandaloneLayout", + docExpansion: "none", + apisSorter: "alpha", + operationsSorter: "method" }) ``` @@ -133,6 +136,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 9058c220..31c1610f 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -4,26 +4,26 @@ Swagger UI - - - - + + + + @@ -34,7 +34,7 @@ - + @@ -67,37 +67,38 @@
- - + + diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index d8487e89..6d04473c 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -197,16 +197,21 @@ export const operationsWithTags = createSelector( } ) -export const taggedOperations = ( state ) =>( { getConfigs } ) => { - let { operationsSorter }= getConfigs() +export const taggedOperations = (state) => ({ getConfigs }) => { + let { apisSorter, operationsSorter } = getConfigs(); - return operationsWithTags(state).map((ops, tag) => { - let sortFn = typeof operationsSorter === "function" ? operationsSorter - : sorters.operationsSorter[operationsSorter] - let operations = !sortFn ? ops : ops.sort(sortFn) + return operationsWithTags(state) + .sort((operationA, operationB) => { + let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]); + return (!sortFn ? null : sortFn(operationA, operationB)); + }) + .map((ops, tag) => { + let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]); + let operations = (!sortFn ? ops : ops.sort(sortFn)); - return Map({tagDetails: tagDetails(state, tag), operations: operations})}) -} + return Map({ tagDetails: tagDetails(state, tag), operations: operations }); + }); +}; export const responses = createSelector( state, diff --git a/src/core/utils.js b/src/core/utils.js index 1412c344..ec3c9fd3 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -562,8 +562,11 @@ export const sorters = { operationsSorter: { alpha: (a, b) => a.get("path").localeCompare(b.get("path")), method: (a, b) => a.get("method").localeCompare(b.get("method")) + }, + apisSorter: { + alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) } -} +}; export const buildFormData = (data) => { let formArr = [] From 24bc8c4b85d300428b7fcfab6b93a6e84d2a1721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 27 Jun 2017 16:45:23 +0200 Subject: [PATCH 02/25] Complying with CI --- src/core/plugins/spec/selectors.js | 16 ++++++++-------- src/core/utils.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index 6d04473c..782f502a 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -198,20 +198,20 @@ export const operationsWithTags = createSelector( ) export const taggedOperations = (state) => ({ getConfigs }) => { - let { apisSorter, operationsSorter } = getConfigs(); + let { apisSorter, operationsSorter } = getConfigs() return operationsWithTags(state) .sort((operationA, operationB) => { - let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]); - return (!sortFn ? null : sortFn(operationA, operationB)); + let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]) + return (!sortFn ? null : sortFn(operationA, operationB)) }) .map((ops, tag) => { - let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]); - let operations = (!sortFn ? ops : ops.sort(sortFn)); + let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]) + let operations = (!sortFn ? ops : ops.sort(sortFn)) - return Map({ tagDetails: tagDetails(state, tag), operations: operations }); - }); -}; + return Map({ tagDetails: tagDetails(state, tag), operations: operations }) + }) +} export const responses = createSelector( state, diff --git a/src/core/utils.js b/src/core/utils.js index ec3c9fd3..a6705209 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -566,7 +566,7 @@ export const sorters = { apisSorter: { alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) } -}; +} export const buildFormData = (data) => { let formArr = [] From d27cae00850b802c87b7bade997923468231d05e Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Wed, 28 Jun 2017 22:07:07 -0600 Subject: [PATCH 03/25] Work on #3102. Moved all the components out of model.jsx into their own files so they can be grabbed via getComponent() --- src/core/components/array-model.jsx | 43 ++++ src/core/components/enum-model.jsx | 19 ++ src/core/components/layouts/base.jsx | 2 +- src/core/components/model-collapse.jsx | 40 ++++ src/core/components/model-example.jsx | 4 +- src/core/components/model-wrapper.jsx | 22 ++ src/core/components/model.jsx | 267 +----------------------- src/core/components/models.jsx | 6 +- src/core/components/object-model.jsx | 104 +++++++++ src/core/components/primitive-model.jsx | 54 +++++ src/core/presets/base.js | 16 +- 11 files changed, 308 insertions(+), 269 deletions(-) create mode 100644 src/core/components/array-model.jsx create mode 100644 src/core/components/enum-model.jsx create mode 100644 src/core/components/model-collapse.jsx create mode 100644 src/core/components/model-wrapper.jsx create mode 100644 src/core/components/object-model.jsx create mode 100644 src/core/components/primitive-model.jsx diff --git a/src/core/components/array-model.jsx b/src/core/components/array-model.jsx new file mode 100644 index 00000000..1a01b0ff --- /dev/null +++ b/src/core/components/array-model.jsx @@ -0,0 +1,43 @@ +import React, { Component, PropTypes } from "react" + +const propStyle = { color: "#999", fontStyle: "italic" } + +export default class ArrayModel extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + getComponent: PropTypes.func.isRequired, + specSelectors: PropTypes.object.isRequired, + name: PropTypes.string, + required: PropTypes.bool, + expandDepth: PropTypes.number, + depth: PropTypes.number + } + + render(){ + let { getComponent, required, schema, depth, expandDepth } = this.props + let items = schema.get("items") + let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 ) + + const ModelCollapse = getComponent("ModelCollapse") + const Model = getComponent("Model") + + return + + { schema.get("title") } + + expandDepth } collapsedContent="[...]"> + [ + + ] + { + properties.size ? + { properties.entrySeq().map( ( [ key, v ] ) => +
{ `${key}:`}{ String(v) }
) + }
+ : null + } +
+ { required && *} +
+ } +} \ No newline at end of file diff --git a/src/core/components/enum-model.jsx b/src/core/components/enum-model.jsx new file mode 100644 index 00000000..78af10da --- /dev/null +++ b/src/core/components/enum-model.jsx @@ -0,0 +1,19 @@ +import React from "react" +import ImPropTypes from "react-immutable-proptypes" + +const EnumModel = ({ value, getComponent }) => { + let ModelCollapse = getComponent("ModelCollapse") + let collapsedContent = Array [ { value.count() } ] + return + Enum:
+ + [ { value.join(", ") } ] + +
+} +EnumModel.propTypes = { + value: ImPropTypes.iterable, + getComponent: ImPropTypes.func +} + +export default EnumModel \ No newline at end of file diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 35cfd7b8..f8132bf0 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -25,7 +25,7 @@ export default class BaseLayout extends React.Component { let Info = getComponent("info") let Operations = getComponent("operations", true) - let Models = getComponent("models", true) + let Models = getComponent("Models", true) let AuthorizeBtn = getComponent("authorizeBtn", true) let Row = getComponent("Row") let Col = getComponent("Col") diff --git a/src/core/components/model-collapse.jsx b/src/core/components/model-collapse.jsx new file mode 100644 index 00000000..256c440e --- /dev/null +++ b/src/core/components/model-collapse.jsx @@ -0,0 +1,40 @@ +import React, { Component, PropTypes } from "react" + +export default class ModelCollapse extends Component { + static propTypes = { + collapsedContent: PropTypes.any, + collapsed: PropTypes.bool, + children: PropTypes.any + } + + static defaultProps = { + collapsedContent: "{...}", + collapsed: true, + } + + constructor(props, context) { + super(props, context) + + let { collapsed, collapsedContent } = this.props + + this.state = { + collapsed: collapsed !== undefined ? collapsed : ModelCollapse.defaultProps.collapsed, + collapsedContent: collapsedContent || ModelCollapse.defaultProps.collapsedContent + } + } + + toggleCollapsed=()=>{ + this.setState({ + collapsed: !this.state.collapsed + }) + } + + render () { + return ( + + + + { this.state.collapsed ? this.state.collapsedContent : this.props.children } + ) + } +} \ No newline at end of file diff --git a/src/core/components/model-example.jsx b/src/core/components/model-example.jsx index 0117c9a5..e7737d12 100644 --- a/src/core/components/model-example.jsx +++ b/src/core/components/model-example.jsx @@ -28,7 +28,7 @@ export default class ModelExample extends React.Component { render() { let { getComponent, specSelectors, schema, example, isExecute } = this.props - const Model = getComponent("model") + const ModelWrapper = getComponent("ModelWrapper") return
    @@ -44,7 +44,7 @@ export default class ModelExample extends React.Component { (isExecute || this.state.activeTab === "example") && example } { - !isExecute && this.state.activeTab === "model" && diff --git a/src/core/components/model-wrapper.jsx b/src/core/components/model-wrapper.jsx new file mode 100644 index 00000000..945633a4 --- /dev/null +++ b/src/core/components/model-wrapper.jsx @@ -0,0 +1,22 @@ +import React, { Component, PropTypes } from "react" + +export default class ModelComponent extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + name: PropTypes.string, + getComponent: PropTypes.func.isRequired, + specSelectors: PropTypes.object.isRequired, + expandDepth: PropTypes.number + } + + render(){ + let { getComponent } = this.props + const Model = getComponent("Model") + + return
    + +
    + } +} + + diff --git a/src/core/components/model.jsx b/src/core/components/model.jsx index a043c325..58e0481d 100644 --- a/src/core/components/model.jsx +++ b/src/core/components/model.jsx @@ -1,208 +1,6 @@ import React, { Component, PropTypes } from "react" -import ImPropTypes from "react-immutable-proptypes" -import { List } from "immutable" -const braceOpen = "{" -const braceClose = "}" -const propStyle = { color: "#999", fontStyle: "italic" } - -const EnumModel = ({ value }) => { - let collapsedContent = Array [ { value.count() } ] - return - Enum:
    - - [ { value.join(", ") } ] - -
    -} - -EnumModel.propTypes = { - value: ImPropTypes.iterable -} - -class ObjectModel extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - name: PropTypes.string, - isRef: PropTypes.bool, - expandDepth: PropTypes.number, - depth: PropTypes.number - } - - render(){ - let { schema, name, isRef, getComponent, depth, ...props } = this.props - let { expandDepth } = this.props - const JumpToPath = getComponent("JumpToPath", true) - let description = schema.get("description") - let properties = schema.get("properties") - let additionalProperties = schema.get("additionalProperties") - let title = schema.get("title") || name - let required = schema.get("required") - const Markdown = getComponent("Markdown") - const JumpToPathSection = ({ name }) => - let collapsedContent = ( - { braceOpen }...{ braceClose } - { - isRef ? : "" - } - ) - - return - { - title && - { isRef && schema.get("$$ref") && { schema.get("$$ref") } } - { title } - - } - expandDepth } collapsedContent={ collapsedContent }> - { braceOpen } - { - !isRef ? null : - } - - { - - { - !description ? null : - - - - } - { - !(properties && properties.size) ? null : properties.entrySeq().map( - ([key, value]) => { - let isRequired = List.isList(required) && required.contains(key) - let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" } - if ( isRequired ) { - propertyStyle.fontWeight = "bold" - } - - return ( - - - ) - }).toArray() - } - { - !additionalProperties || !additionalProperties.size ? null - : - - - - } -
    description: - -
    { key }: - -
    { "< * >:" } - -
    - } -
    - { braceClose } -
    -
    - } -} - -class Primitive extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - required: PropTypes.bool - } - - render(){ - let { schema, getComponent, required } = this.props - - if(!schema || !schema.get) { - // don't render if schema isn't correctly formed - return
    - } - - let type = schema.get("type") - let format = schema.get("format") - let xml = schema.get("xml") - let enumArray = schema.get("enum") - let description = schema.get("description") - let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 ) - let style = required ? { fontWeight: "bold" } : {} - const Markdown = getComponent("Markdown") - - return - { type } { required && *} - { format && (${format})} - { - properties.size ? properties.entrySeq().map( ( [ key, v ] ) => -
    { key }: { String(v) }
    ) - : null - } - { - !description ? null : - - } - { - xml && xml.size ? (
    xml: - { - xml.entrySeq().map( ( [ key, v ] ) =>
       {key}: { String(v) }
    ).toArray() - } -
    ): null - } - { - enumArray && - } -
    - } -} - -class ArrayModel extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - name: PropTypes.string, - required: PropTypes.bool, - expandDepth: PropTypes.number, - depth: PropTypes.number - } - - render(){ - let { required, schema, depth, expandDepth } = this.props - let items = schema.get("items") - let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 ) - - return - - { schema.get("title") } - - expandDepth } collapsedContent="[...]"> - [ - - ] - { - properties.size ? - { properties.entrySeq().map( ( [ key, v ] ) => -
    { `${key}:`}{ String(v) }
    ) - }
    - : null - } -
    - { required && *} -
    - } -} - - -class Model extends Component { +export default class Model extends Component { static propTypes = { schema: PropTypes.object.isRequired, getComponent: PropTypes.func.isRequired, @@ -228,6 +26,9 @@ class Model extends Component { render () { let { schema, getComponent, required, name, isRef } = this.props + let ObjectModel = getComponent("ObjectModel") + let ArrayModel = getComponent("ArrayModel") + let PrimitiveModel = getComponent("PrimitiveModel") let $$ref = schema && schema.get("$$ref") let modelName = $$ref && this.getModelName( $$ref ) let modelSchema, type @@ -255,63 +56,7 @@ class Model extends Component { case "integer": case "boolean": default: - return + return } } -} - - -export default class ModelComponent extends Component { - static propTypes = { - schema: PropTypes.object.isRequired, - name: PropTypes.string, - getComponent: PropTypes.func.isRequired, - specSelectors: PropTypes.object.isRequired, - expandDepth: PropTypes.number - } - - render(){ - return
    - -
    - } -} - -class Collapse extends Component { - static propTypes = { - collapsedContent: PropTypes.any, - collapsed: PropTypes.bool, - children: PropTypes.any - } - - static defaultProps = { - collapsedContent: "{...}", - collapsed: true, - } - - constructor(props, context) { - super(props, context) - - let { collapsed, collapsedContent } = this.props - - this.state = { - collapsed: collapsed !== undefined ? collapsed : Collapse.defaultProps.collapsed, - collapsedContent: collapsedContent || Collapse.defaultProps.collapsedContent - } - } - - toggleCollapsed=()=>{ - this.setState({ - collapsed: !this.state.collapsed - }) - } - - render () { - return ( - - - - { this.state.collapsed ? this.state.collapsedContent : this.props.children } - ) - } -} +} \ No newline at end of file diff --git a/src/core/components/models.jsx b/src/core/components/models.jsx index 21605199..c311f350 100644 --- a/src/core/components/models.jsx +++ b/src/core/components/models.jsx @@ -1,6 +1,5 @@ import React, { Component, PropTypes } from "react" - export default class Models extends Component { static propTypes = { getComponent: PropTypes.func, @@ -16,7 +15,7 @@ export default class Models extends Component { let { docExpansion } = getConfigs() let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" ) - const Model = getComponent("model") + const ModelWrapper = getComponent("ModelWrapper") const Collapse = getComponent("Collapse") if (!definitions.size) return null @@ -31,8 +30,9 @@ export default class Models extends Component { { definitions.entrySeq().map( ( [ name, model ])=>{ + console.log("model", name, model) return
    - + const collapsedContent = ( + { braceOpen }...{ braceClose } + { + isRef ? : "" + } + ) + + + return + { + title && + { isRef && schema.get("$$ref") && { schema.get("$$ref") } } + { title } + + } + expandDepth } collapsedContent={ collapsedContent }> + { braceOpen } + { + !isRef ? null : + } + + { + + { + !description ? null : + + + + } + { + !(properties && properties.size) ? null : properties.entrySeq().map( + ([key, value]) => { + let isRequired = List.isList(required) && required.contains(key) + let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" } + if ( isRequired ) { + propertyStyle.fontWeight = "bold" + } + + return ( + + + ) + }).toArray() + } + { + !additionalProperties || !additionalProperties.size ? null + : + + + + } +
    description: + +
    { key }: + +
    { "< * >:" } + +
    + } +
    + { braceClose } +
    +
    + } +} \ No newline at end of file diff --git a/src/core/components/primitive-model.jsx b/src/core/components/primitive-model.jsx new file mode 100644 index 00000000..24363187 --- /dev/null +++ b/src/core/components/primitive-model.jsx @@ -0,0 +1,54 @@ +import React, { Component, PropTypes } from "react" + +const propStyle = { color: "#999", fontStyle: "italic" } + +export default class Primitive extends Component { + static propTypes = { + schema: PropTypes.object.isRequired, + getComponent: PropTypes.func.isRequired, + required: PropTypes.bool + } + + render(){ + let { schema, getComponent, required } = this.props + + if(!schema || !schema.get) { + // don't render if schema isn't correctly formed + return
    + } + + let type = schema.get("type") + let format = schema.get("format") + let xml = schema.get("xml") + let enumArray = schema.get("enum") + let description = schema.get("description") + let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 ) + let style = required ? { fontWeight: "bold" } : {} + const Markdown = getComponent("Markdown") + const EnumModel = getComponent("EnumModel") + + return + { type } { required && *} + { format && (${format})} + { + properties.size ? properties.entrySeq().map( ( [ key, v ] ) => +
    { key }: { String(v) }
    ) + : null + } + { + !description ? null : + + } + { + xml && xml.size ? (
    xml: + { + xml.entrySeq().map( ( [ key, v ] ) =>
       {key}: { String(v) }
    ).toArray() + } +
    ): null + } + { + enumArray && + } +
    + } +} \ No newline at end of file diff --git a/src/core/presets/base.js b/src/core/presets/base.js index 20ff4659..d5471791 100644 --- a/src/core/presets/base.js +++ b/src/core/presets/base.js @@ -41,9 +41,15 @@ import Footer from "core/components/footer" import ParamBody from "core/components/param-body" import Curl from "core/components/curl" import Schemes from "core/components/schemes" +import ModelCollapse from "core/components/model-collapse" import ModelExample from "core/components/model-example" +import ModelWrapper from "core/components/model-wrapper" import Model from "core/components/model" import Models from "core/components/models" +import EnumModel from "core/components/enum-model" +import ObjectModel from "core/components/object-model" +import ArrayModel from "core/components/array-model" +import PrimitiveModel from "core/components/primitive-model" import TryItOutButton from "core/components/try-it-out-button" import Markdown from "core/components/providers/markdown" @@ -88,8 +94,14 @@ export default function() { curl: Curl, schemes: Schemes, modelExample: ModelExample, - model: Model, - models: Models, + ModelWrapper, + ModelCollapse, + Model, + Models, + EnumModel, + ObjectModel, + ArrayModel, + PrimitiveModel, TryItOutButton, Markdown, BaseLayout From 6fd5839103a6f6d345c0289d07ab50bd79d6f2dd Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Mon, 3 Jul 2017 16:27:47 -0600 Subject: [PATCH 04/25] Fix PropTypes in model-collapse component --- src/core/components/model-collapse.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/components/model-collapse.jsx b/src/core/components/model-collapse.jsx index 256c440e..1b46e56a 100644 --- a/src/core/components/model-collapse.jsx +++ b/src/core/components/model-collapse.jsx @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from "react" +import React, { Component } from "react" +import PropTypes from "prop-types" export default class ModelCollapse extends Component { static propTypes = { From 4bfb392e4994064288a6d3b85fb22c319d0e2c6e Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Mon, 3 Jul 2017 16:41:10 -0700 Subject: [PATCH 05/25] Undo changed defaults --- README.md | 7 ++----- dev-helpers/index.html | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a62a18ab..c7f02194 100644 --- a/README.md +++ b/README.md @@ -91,10 +91,7 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" + layout: "StandaloneLayout" }) ``` @@ -147,7 +144,7 @@ parameterMacro | MUST be a function. Function to set default value to parameters modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable docExpansion | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default is 'list'. displayOperationId | Controls the display of operationId in operations list. The default is `false`. -displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`. +displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`. ### Plugins diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 31c1610f..b23ec6f8 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -84,10 +84,7 @@ plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" + layout: "StandaloneLayout" }); ui.initOAuth({ From 8ce2b309d84136c827b0d62b6880f2eb7e7bcdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 4 Jul 2017 09:15:43 +0200 Subject: [PATCH 06/25] Complying with request for changes --- README.md | 27 ++++++++++++--------------- dev-helpers/index.html | 41 ++++++++++++++++++++--------------------- src/core/index.js | 2 ++ 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index a62a18ab..49523da1 100644 --- a/README.md +++ b/README.md @@ -82,20 +82,17 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui ```javascript const ui = SwaggerUIBundle({ - url: "http://petstore.swagger.io/v2/swagger.json", - dom_id: '#swagger-ui', - presets: [ - SwaggerUIBundle.presets.apis, - SwaggerUIStandalonePreset - ], - plugins: [ - SwaggerUIBundle.plugins.DownloadUrl - ], - layout: "StandaloneLayout", - docExpansion: "none", - apisSorter: "alpha", - operationsSorter: "method" - }) + url: "http://petstore.swagger.io/v2/swagger.json", + dom_id: '#swagger-ui', + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + layout: "StandaloneLayout" + }) ``` #### OAuth2 configuration @@ -140,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL -apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order detemrined by Swagger-UI. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable diff --git a/dev-helpers/index.html b/dev-helpers/index.html index 31c1610f..a528687b 100644 --- a/dev-helpers/index.html +++ b/dev-helpers/index.html @@ -4,26 +4,26 @@ Swagger UI - - - - + + + + @@ -67,14 +67,14 @@
    - - + + diff --git a/src/core/index.js b/src/core/index.js index 80335da5..26ab44b4 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -26,6 +26,8 @@ module.exports = function SwaggerUI(opts) { urls: null, layout: "BaseLayout", docExpansion: "list", + apisSorter: "alpha", + operationsSorter: "method", validatorUrl: "https://online.swagger.io/validator", configs: {}, custom: {}, From d031413d92d853fb48b4a4fda50ce6616a86240f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 4 Jul 2017 09:20:55 +0200 Subject: [PATCH 07/25] Fix typo in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 630fefe1..94f874b0 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL -apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order detemrined by Swagger-UI. +apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order determined by Swagger-UI. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable From d8400f872999c7ca50704e03ccd450f98ce25840 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 9 Jul 2017 14:17:18 -0600 Subject: [PATCH 08/25] Fixes #3300 - Updates to versions.swaggerUi information --- make-webpack-config.js | 66 ++++++++++++++++++++++-------------------- src/core/index.js | 10 +++++-- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/make-webpack-config.js b/make-webpack-config.js index f2628bc0..2a6ed131 100644 --- a/make-webpack-config.js +++ b/make-webpack-config.js @@ -1,11 +1,12 @@ -var path = require('path') +var path = require("path") -var webpack = require('webpack') -var ExtractTextPlugin = require('extract-text-webpack-plugin') -var deepExtend = require('deep-extend') -const {gitDescribeSync} = require('git-describe'); +var webpack = require("webpack") +var ExtractTextPlugin = require("extract-text-webpack-plugin") +var deepExtend = require("deep-extend") +const {gitDescribeSync} = require("git-describe") +const os = require("os") -var pkg = require('./package.json') +var pkg = require("./package.json") let gitInfo @@ -13,7 +14,7 @@ try { gitInfo = gitDescribeSync(__dirname) } catch(e) { gitInfo = { - hash: 'noGit', + hash: "noGit", dirty: false } } @@ -21,21 +22,21 @@ try { var commonRules = [ { test: /\.(js(x)?)(\?.*)?$/, use: [{ - loader: 'babel-loader', + loader: "babel-loader", options: { retainLines: true } }], - include: [ path.join(__dirname, 'src') ] + include: [ path.join(__dirname, "src") ] }, { test: /\.(txt|yaml)(\?.*)?$/, - loader: 'raw-loader' }, + loader: "raw-loader" }, { test: /\.(png|jpg|jpeg|gif|svg)(\?.*)?$/, - loader: 'url-loader?limit=10000' }, + loader: "url-loader?limit=10000" }, { test: /\.(woff|woff2)(\?.*)?$/, - loader: 'url-loader?limit=100000' }, + loader: "url-loader?limit=100000" }, { test: /\.(ttf|eot)(\?.*)?$/, - loader: 'file-loader' } + loader: "file-loader" } ] module.exports = function(rules, options) { @@ -54,7 +55,7 @@ module.exports = function(rules, options) { if( specialOptions.separateStylesheets ) { plugins.push(new ExtractTextPlugin({ - filename: '[name].css' + (specialOptions.longTermCaching ? '?[contenthash]' : ''), + filename: "[name].css" + (specialOptions.longTermCaching ? "?[contenthash]" : ""), allChunks: true })) } @@ -78,35 +79,36 @@ module.exports = function(rules, options) { plugins.push( new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: specialOptions.minimize ? JSON.stringify('production') : null, - WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets) - + "process.env": { + NODE_ENV: specialOptions.minimize ? JSON.stringify("production") : null, + WEBPACK_INLINE_STYLES: !specialOptions.separateStylesheets }, - 'buildInfo': JSON.stringify({ + "buildInfo": JSON.stringify({ PACKAGE_VERSION: (pkg.version), GIT_COMMIT: gitInfo.hash, - GIT_DIRTY: gitInfo.dirty + GIT_DIRTY: gitInfo.dirty, + HOSTNAME: os.hostname(), + BUILD_TIME: new Date().toUTCString() }) })) delete options._special - var completeConfig = deepExtend({ + var completeConfig = deepExtend({ entry: {}, output: { - path: path.join(__dirname, 'dist'), - publicPath: '/', - filename: '[name].js', - chunkFilename: '[name].js' + path: path.join(__dirname, "dist"), + publicPath: "/", + filename: "[name].js", + chunkFilename: "[name].js" }, - target: 'web', + target: "web", // yaml-js has a reference to `fs`, this is a workaround node: { - fs: 'empty' + fs: "empty" }, module: { @@ -114,17 +116,17 @@ module.exports = function(rules, options) { }, resolveLoader: { - modules: [path.join(__dirname, 'node_modules')], + modules: [path.join(__dirname, "node_modules")], }, externals: { - 'buffertools': true // json-react-schema/deeper depends on buffertools, which fails. + "buffertools": true // json-react-schema/deeper depends on buffertools, which fails. }, resolve: { modules: [ - path.join(__dirname, './src'), - 'node_modules' + path.join(__dirname, "./src"), + "node_modules" ], extensions: [".web.js", ".js", ".jsx", ".json", ".less"], alias: { @@ -132,7 +134,7 @@ module.exports = function(rules, options) { } }, - devtool: specialOptions.sourcemaps ? 'cheap-module-source-map' : null, + devtool: specialOptions.sourcemaps ? "cheap-module-source-map" : null, plugins, diff --git a/src/core/index.js b/src/core/index.js index 80335da5..ed6768e1 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -11,12 +11,18 @@ const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "on "showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"] // eslint-disable-next-line no-undef -const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo +const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo module.exports = function SwaggerUI(opts) { win.versions = win.versions || {} - win.versions.swaggerUi = `${PACKAGE_VERSION}/${GIT_COMMIT || "unknown"}${GIT_DIRTY ? "-dirty" : ""}` + win.versions.swaggerUi = { + version: PACKAGE_VERSION, + gitRevision: GIT_COMMIT, + gitDirty: GIT_DIRTY, + buildTimestamp: BUILD_TIME, + machine: HOSTNAME + } const defaults = { // Some general settings, that we floated to the top From c3f9c094d1b6761c2a847f5c807aac86120402b6 Mon Sep 17 00:00:00 2001 From: Gwyn Judd Date: Wed, 7 Jun 2017 16:29:46 +1200 Subject: [PATCH 09/25] Added maxRows and filter support Useful for the display of very large swagger specs. Can limit the number of operations to a smaller value and search --- README.md | 2 ++ src/core/components/layouts/base.jsx | 7 ++++--- src/core/components/operations.jsx | 18 ++++++++++++++++-- src/core/index.js | 4 +++- src/plugins/topbar/topbar.jsx | 15 +++++++++++++++ src/standalone/layout.jsx | 24 +++++++++++++++++++++--- 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c872e4c5..28943fab 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ modelPropertyMacro | MUST be a function. Function to set default values to each docExpansion | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default is 'list'. displayOperationId | Controls the display of operationId in operations list. The default is `false`. displayRequestDuration | Controls the display of the request duration (in milliseconds) for `Try it out` requests. The default is `false`. +maxDisplayedTags | If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations. +filter | If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that are shown. Can be true/false to enable or disable, or an explicit filter string in which case filtering will be enabled using that string as the filter expression. Filtering is case sensitive matching the filter expression anywhere inside the tag. ### Plugins diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 9da4b347..7e927c0b 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -10,11 +10,12 @@ export default class BaseLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired + getComponent: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired } render() { - let { specSelectors, specActions, getComponent } = this.props + let { specSelectors, specActions, getComponent, filter } = this.props let info = specSelectors.info() let url = specSelectors.url() @@ -66,7 +67,7 @@ export default class BaseLayout extends React.Component { - + diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index 6c20d963..fff1b226 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -11,7 +11,8 @@ export default class Operations extends React.Component { layoutActions: PropTypes.object.isRequired, authActions: PropTypes.object.isRequired, authSelectors: PropTypes.object.isRequired, - getConfigs: PropTypes.func.isRequired + getConfigs: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired }; render() { @@ -24,6 +25,7 @@ export default class Operations extends React.Component { authActions, authSelectors, getConfigs, + filter, fn } = this.props @@ -33,7 +35,19 @@ export default class Operations extends React.Component { const Collapse = getComponent("Collapse") let showSummary = layoutSelectors.showSummary() - let { docExpansion, displayOperationId, displayRequestDuration } = getConfigs() + let { docExpansion, displayOperationId, displayRequestDuration, maxDisplayedTags } = getConfigs() + + if (filter) { + if (filter !== true) { + taggedOps = taggedOps.filter((tagObj, tag) => { + return tag.indexOf(filter) !== -1 + }) + } + } + + if (maxDisplayedTags && !isNaN(maxDisplayedTags) && maxDisplayedTags >= 0) { + taggedOps = taggedOps.slice(0, maxDisplayedTags) + } return (
    diff --git a/src/core/index.js b/src/core/index.js index 80335da5..381748d4 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -6,7 +6,7 @@ import ApisPreset from "core/presets/apis" import * as AllPlugins from "core/plugins/all" import { parseSeach, filterConfigs } from "core/utils" -const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion", +const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion", "maxDisplayedTags", "filter", "apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl", "showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"] @@ -26,6 +26,8 @@ module.exports = function SwaggerUI(opts) { urls: null, layout: "BaseLayout", docExpansion: "list", + maxDisplayedTags: null, + filter: null, validatorUrl: "https://online.swagger.io/validator", configs: {}, custom: {}, diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index 11b5c7eb..087b3c93 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -6,6 +6,11 @@ import Logo from "./logo_small.png" export default class Topbar extends React.Component { + static propTypes = { + onFilterChange: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired + } + constructor(props, context) { super(props, context) this.state = { url: props.specSelectors.url(), selectedIndex: 0 } @@ -80,6 +85,11 @@ export default class Topbar extends React.Component { } } + onFilterChange =(e) => { + let {target: {value}} = e + this.props.onFilterChange(value) + } + render() { let { getComponent, specSelectors, getConfigs } = this.props const Button = getComponent("Button") @@ -87,6 +97,7 @@ export default class Topbar extends React.Component { let isLoading = specSelectors.loadingStatus() === "loading" let isFailed = specSelectors.loadingStatus() === "failed" + let filter = this.props.filter let inputStyle = {} if(isFailed) inputStyle.color = "red" @@ -124,6 +135,10 @@ export default class Topbar extends React.Component { Swagger UX swagger + { + filter === null || filter === false ? null : + + }
    {control}
    diff --git a/src/standalone/layout.jsx b/src/standalone/layout.jsx index 20ca50d1..783b9a1c 100644 --- a/src/standalone/layout.jsx +++ b/src/standalone/layout.jsx @@ -10,7 +10,23 @@ export default class StandaloneLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired + getComponent: PropTypes.func.isRequired, + getConfigs: PropTypes.func.isRequired + } + + constructor(props) { + super(props) + + this.handleFilterChange = this.handleFilterChange.bind(this) + + let { getConfigs } = this.props + let { filter } = getConfigs() + + this.state = { filter: filter } + } + + handleFilterChange(filter) { + this.setState({ filter: filter }) } render() { @@ -24,12 +40,14 @@ export default class StandaloneLayout extends React.Component { const BaseLayout = getComponent("BaseLayout", true) const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true) + const filter = this.state.filter + const loadingStatus = specSelectors.loadingStatus() return ( - { Topbar ? : null } + { Topbar ? : null } { loadingStatus === "loading" &&

    Loading...

    @@ -45,7 +63,7 @@ export default class StandaloneLayout extends React.Component {

    Failed to load config.

    } - { !loadingStatus || loadingStatus === "success" && } + { !loadingStatus || loadingStatus === "success" && } From fe200f86167b42343ad784436267dc7a3ef2d119 Mon Sep 17 00:00:00 2001 From: Minasokoni Date: Fri, 7 Jul 2017 15:01:58 -0700 Subject: [PATCH 10/25] styling updates --- src/style/_layout.scss | 48 ++++++++++++++++++++++++------------------ src/style/_topbar.scss | 8 ++++++- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/style/_layout.scss b/src/style/_layout.scss index 955e4d54..78e09249 100644 --- a/src/style/_layout.scss +++ b/src/style/_layout.scss @@ -45,6 +45,7 @@ body .opblock-tag { display: flex; + align-items: center; padding: 10px 20px 10px 10px; @@ -53,8 +54,6 @@ body border-bottom: 1px solid rgba(#3b4151, .3); - align-items: center; - &:hover { background: rgba(#000,.02); @@ -106,9 +105,10 @@ body font-size: 14px; font-weight: normal; + flex: 1; + padding: 0 10px; - flex: 1; @include text_body(); } } @@ -134,6 +134,8 @@ body transition: all .5s; } + + .opblock { margin: 0 0 15px 0; @@ -154,24 +156,23 @@ body .opblock-section-header { display: flex; + align-items: center; padding: 8px 20px; background: rgba(#fff,.8); box-shadow: 0 1px 2px rgba(#000,.1); - align-items: center; - label { font-size: 12px; font-weight: bold; display: flex; + align-items: center; margin: 0; - align-items: center; @include text_headline(); span @@ -184,9 +185,10 @@ body { font-size: 14px; + flex: 1; + margin: 0; - flex: 1; @include text_headline(); } } @@ -215,11 +217,11 @@ body font-size: 16px; display: flex; + align-items: center; padding: 0 10px; @include text_code(); - align-items: center; .view-line-link { @@ -258,18 +260,18 @@ body font-size: 13px; flex: 1; + @include text_body(); } .opblock-summary { display: flex; + align-items: center; padding: 5px; cursor: pointer; - - align-items: center; } &.opblock-post @@ -316,12 +318,12 @@ body .opblock-schemes { - padding: 8px 20px; + padding: 8px 20px; - .schemes-title - { - padding: 0 10px 0 0; - } + .schemes-title + { + padding: 0 10px 0 0; + } } } @@ -498,13 +500,11 @@ body margin: 0; padding: 10px; - + white-space: pre-wrap; word-wrap: break-word; word-break: break-all; word-break: break-word; hyphens: auto; - white-space: pre-wrap; - border-radius: 4px; background: #41444e; @@ -533,10 +533,9 @@ body .schemes { display: flex; - align-items: center; - > label + > label { font-size: 12px; font-weight: bold; @@ -624,3 +623,12 @@ body opacity: 0; } } + + +section +{ + h3 + { + @include text_headline(); + } +} diff --git a/src/style/_topbar.scss b/src/style/_topbar.scss index 4bded694..b1427c78 100644 --- a/src/style/_topbar.scss +++ b/src/style/_topbar.scss @@ -29,6 +29,12 @@ padding: 0 10px; } } + .operation-filter-input + { + border: 2px solid #547f00; + border-right: none; + border-radius: 4px 0 0 4px; + } .download-url-wrapper { @@ -43,7 +49,7 @@ margin: 0; border: 2px solid #547f00; - border-radius: 4px 0 0 4px; + border-radius: 0 0 0 0; outline: none; } From 297ee610384440f65673ed81867894a9dcbf9a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20MARQUES?= Date: Tue, 11 Jul 2017 21:13:30 +0200 Subject: [PATCH 11/25] Update index.js --- src/core/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/index.js b/src/core/index.js index 26ab44b4..80335da5 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -26,8 +26,6 @@ module.exports = function SwaggerUI(opts) { urls: null, layout: "BaseLayout", docExpansion: "list", - apisSorter: "alpha", - operationsSorter: "method", validatorUrl: "https://online.swagger.io/validator", configs: {}, custom: {}, From cf12091d9323251e9b18ee5f46d3b9335942af1f Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Tue, 11 Jul 2017 21:33:14 -0700 Subject: [PATCH 12/25] Add filter to layout state --- src/core/index.js | 3 ++- src/core/plugins/layout/actions.js | 8 ++++++++ src/core/plugins/layout/reducers.js | 3 +++ src/core/plugins/layout/selectors.js | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/core/index.js b/src/core/index.js index 381748d4..dbfee248 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -61,7 +61,8 @@ module.exports = function SwaggerUI(opts) { plugins: constructorConfig.presets, state: { layout: { - layout: constructorConfig.layout + layout: constructorConfig.layout, + filter: constructorConfig.filter }, spec: { spec: "", diff --git a/src/core/plugins/layout/actions.js b/src/core/plugins/layout/actions.js index b8cba718..d65d34e3 100644 --- a/src/core/plugins/layout/actions.js +++ b/src/core/plugins/layout/actions.js @@ -1,6 +1,7 @@ import { normalizeArray } from "core/utils" export const UPDATE_LAYOUT = "layout_update_layout" +export const UPDATE_FILTER = "layout_update_filter" export const UPDATE_MODE = "layout_update_mode" export const SHOW = "layout_show" @@ -13,6 +14,13 @@ export function updateLayout(layout) { } } +export function updateFilter(filter) { + return { + type: UPDATE_FILTER, + payload: filter + } +} + export function show(thing, shown=true) { thing = normalizeArray(thing) return { diff --git a/src/core/plugins/layout/reducers.js b/src/core/plugins/layout/reducers.js index 44e3c480..4b561015 100644 --- a/src/core/plugins/layout/reducers.js +++ b/src/core/plugins/layout/reducers.js @@ -1,5 +1,6 @@ import { UPDATE_LAYOUT, + UPDATE_FILTER, UPDATE_MODE, SHOW } from "./actions" @@ -8,6 +9,8 @@ export default { [UPDATE_LAYOUT]: (state, action) => state.set("layout", action.payload), + [UPDATE_FILTER]: (state, action) => state.set("filter", action.payload), + [SHOW]: (state, action) => { let thing = action.payload.thing let shown = action.payload.shown diff --git a/src/core/plugins/layout/selectors.js b/src/core/plugins/layout/selectors.js index 0eb0c522..42a3bcbb 100644 --- a/src/core/plugins/layout/selectors.js +++ b/src/core/plugins/layout/selectors.js @@ -5,6 +5,8 @@ const state = state => state export const current = state => state.get("layout") +export const currentFilter = state => state.get("filter") + export const isShown = (state, thing, def) => { thing = normalizeArray(thing) return Boolean(state.getIn(["shown", ...thing], def)) From 28f7a15fe9b0f3ec4b32a300d41c7e5a2eb7be69 Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Tue, 11 Jul 2017 21:54:56 -0700 Subject: [PATCH 13/25] Use state instead of component hand-down for managing filter --- src/core/components/layouts/base.jsx | 7 +++---- src/core/components/operations.jsx | 3 ++- src/core/index.js | 5 +++-- src/plugins/topbar/topbar.jsx | 10 +++++----- src/standalone/layout.jsx | 24 +++--------------------- 5 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 3240e65a..3e6c7139 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -10,12 +10,11 @@ export default class BaseLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - filter: PropTypes.string.isRequired + getComponent: PropTypes.func.isRequired } render() { - let { specSelectors, specActions, getComponent, filter } = this.props + let { specSelectors, specActions, getComponent } = this.props let info = specSelectors.info() let url = specSelectors.url() @@ -67,7 +66,7 @@ export default class BaseLayout extends React.Component { - + diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index fff1b226..75ab089d 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -25,7 +25,6 @@ export default class Operations extends React.Component { authActions, authSelectors, getConfigs, - filter, fn } = this.props @@ -37,6 +36,8 @@ export default class Operations extends React.Component { let showSummary = layoutSelectors.showSummary() let { docExpansion, displayOperationId, displayRequestDuration, maxDisplayedTags } = getConfigs() + let filter = layoutSelectors.currentFilter() + if (filter) { if (filter !== true) { taggedOps = taggedOps.filter((tagObj, tag) => { diff --git a/src/core/index.js b/src/core/index.js index dbfee248..2796730f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -52,7 +52,9 @@ module.exports = function SwaggerUI(opts) { store: { }, } - const constructorConfig = deepExtend({}, defaults, opts) + let queryConfig = parseSeach() + + const constructorConfig = deepExtend({}, defaults, opts, queryConfig) const storeConfigs = deepExtend({}, constructorConfig.store, { system: { @@ -83,7 +85,6 @@ module.exports = function SwaggerUI(opts) { store.register([constructorConfig.plugins, inlinePlugin]) var system = store.getSystem() - let queryConfig = parseSeach() system.initOAuth = system.authActions.configureAuth diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index 087b3c93..314e1d4e 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -7,8 +7,8 @@ import Logo from "./logo_small.png" export default class Topbar extends React.Component { static propTypes = { - onFilterChange: PropTypes.func.isRequired, - filter: PropTypes.string.isRequired + layoutSelectors: PropTypes.object.isRequired, + layoutActions: PropTypes.object.isRequired } constructor(props, context) { @@ -87,17 +87,17 @@ export default class Topbar extends React.Component { onFilterChange =(e) => { let {target: {value}} = e - this.props.onFilterChange(value) + this.props.layoutActions.updateFilter(value) } render() { - let { getComponent, specSelectors, getConfigs } = this.props + let { getComponent, specSelectors, getConfigs, layoutSelectors } = this.props const Button = getComponent("Button") const Link = getComponent("Link") let isLoading = specSelectors.loadingStatus() === "loading" let isFailed = specSelectors.loadingStatus() === "failed" - let filter = this.props.filter + let filter = layoutSelectors.currentFilter() let inputStyle = {} if(isFailed) inputStyle.color = "red" diff --git a/src/standalone/layout.jsx b/src/standalone/layout.jsx index 783b9a1c..dc36b46e 100644 --- a/src/standalone/layout.jsx +++ b/src/standalone/layout.jsx @@ -10,23 +10,7 @@ export default class StandaloneLayout extends React.Component { specSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired, - getComponent: PropTypes.func.isRequired, - getConfigs: PropTypes.func.isRequired - } - - constructor(props) { - super(props) - - this.handleFilterChange = this.handleFilterChange.bind(this) - - let { getConfigs } = this.props - let { filter } = getConfigs() - - this.state = { filter: filter } - } - - handleFilterChange(filter) { - this.setState({ filter: filter }) + getComponent: PropTypes.func.isRequired } render() { @@ -40,14 +24,12 @@ export default class StandaloneLayout extends React.Component { const BaseLayout = getComponent("BaseLayout", true) const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true) - const filter = this.state.filter - const loadingStatus = specSelectors.loadingStatus() return ( - { Topbar ? : null } + { Topbar ? : null } { loadingStatus === "loading" &&

    Loading...

    @@ -63,7 +45,7 @@ export default class StandaloneLayout extends React.Component {

    Failed to load config.

    } - { !loadingStatus || loadingStatus === "success" && } + { !loadingStatus || loadingStatus === "success" && } From 66c8778a292dc94a9bb91ff810e62d17a6d064fa Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Tue, 11 Jul 2017 22:05:38 -0700 Subject: [PATCH 14/25] Remove obsolete prop from validation --- src/core/components/operations.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/components/operations.jsx b/src/core/components/operations.jsx index 75ab089d..679af129 100644 --- a/src/core/components/operations.jsx +++ b/src/core/components/operations.jsx @@ -11,8 +11,7 @@ export default class Operations extends React.Component { layoutActions: PropTypes.object.isRequired, authActions: PropTypes.object.isRequired, authSelectors: PropTypes.object.isRequired, - getConfigs: PropTypes.func.isRequired, - filter: PropTypes.string.isRequired + getConfigs: PropTypes.func.isRequired }; render() { From 991ae66b3951fd6455d0604b4f9f9b3c4a16204b Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Wed, 12 Jul 2017 19:56:11 -0600 Subject: [PATCH 15/25] Fixes #3375 - Change order of logic for selecting `requestContentType` to prioritize `consumes_value` first --- src/core/plugins/spec/selectors.js | 11 ++--- test/core/plugins/spec/selectors.js | 68 ++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index a4f94349..cd7e722b 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -277,12 +277,13 @@ export function parametersIncludeType(parameters, typeValue="") { export function contentTypeValues(state, pathMethod) { let op = spec(state).getIn(["paths", ...pathMethod], fromJS({})) const parameters = op.get("parameters") || new List() - const requestContentType = ( - parametersIncludeType(parameters, "file") ? "multipart/form-data" - : parametersIncludeIn(parameters, "formData") ? "application/x-www-form-urlencoded" - : op.get("consumes_value") - ) + const requestContentType = ( + op.get("consumes_value") ? op.get("consumes_value") + : parametersIncludeType(parameters, "file") ? "multipart/form-data" + : parametersIncludeType(parameters, "formData") ? "application/x-www-form-urlencoded" + : undefined + ) return fromJS({ requestContentType, diff --git a/test/core/plugins/spec/selectors.js b/test/core/plugins/spec/selectors.js index 93abd025..7519a42e 100644 --- a/test/core/plugins/spec/selectors.js +++ b/test/core/plugins/spec/selectors.js @@ -52,7 +52,6 @@ describe("spec plugin - selectors", function(){ }) describe("contentTypeValues", function(){ - it("should return { requestContentType, responseContentType } from an operation", function(){ // Given let state = fromJS({ @@ -77,6 +76,73 @@ describe("spec plugin - selectors", function(){ }) }) + it("should prioritize consumes value first from an operation", function(){ + // Given + let state = fromJS({ + resolved: { + paths: { + "/one": { + get: { + "consumes_value": "one", + "parameters": [{ + "type": "file" + }], + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("one") + }) + + it("should fallback to multipart/form-data if there is no consumes value but there is a file parameter", function(){ + // Given + let state = fromJS({ + resolved: { + paths: { + "/one": { + get: { + "parameters": [{ + "type": "file" + }], + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("multipart/form-data") + }) + + it("should fallback to application/x-www-form-urlencoded if there is no consumes value, no file parameter, but there is a formData parameter", function(){ + // Given + let state = fromJS({ + resolved: { + paths: { + "/one": { + get: { + "parameters": [{ + "type": "formData" + }], + } + } + } + } + }) + + // When + let contentTypes = contentTypeValues(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS().requestContentType).toEqual("application/x-www-form-urlencoded") + }) + it("should be ok, if no operation found", function(){ // Given let state = fromJS({ }) From 571d65a5829e5b4d352fe126f251e045a1cef16f Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Thu, 13 Jul 2017 20:36:08 -0700 Subject: [PATCH 16/25] apisSorter -> tagsSorter "tags", not "tag", because it sorts the tags themselves, not the content of each tag. --- README.md | 2 +- src/core/index.js | 2 +- src/core/plugins/spec/selectors.js | 4 ++-- src/core/utils.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e8ab9616..d076f377 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL -apisSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order determined by Swagger-UI. +tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order determined by Swagger-UI. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable diff --git a/src/core/index.js b/src/core/index.js index 80335da5..24bf8d94 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -7,7 +7,7 @@ import * as AllPlugins from "core/plugins/all" import { parseSeach, filterConfigs } from "core/utils" const CONFIGS = [ "url", "urls", "urls.primaryName", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion", - "apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl", + "tagsSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl", "showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" , "displayRequestDuration"] // eslint-disable-next-line no-undef diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index a67dc28b..c9b31cf1 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -201,11 +201,11 @@ export const operationsWithTags = createSelector( ) export const taggedOperations = (state) => ({ getConfigs }) => { - let { apisSorter, operationsSorter } = getConfigs() + let { tagsSorter, operationsSorter } = getConfigs() return operationsWithTags(state) .sort((operationA, operationB) => { - let sortFn = (typeof apisSorter === "function" ? apisSorter : sorters.apisSorter[ apisSorter ]) + let sortFn = (typeof tagsSorter === "function" ? tagsSorter : sorters.tagsSorter[ tagsSorter ]) return (!sortFn ? null : sortFn(operationA, operationB)) }) .map((ops, tag) => { diff --git a/src/core/utils.js b/src/core/utils.js index eb6e0a0e..f4b925f6 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -575,7 +575,7 @@ export const sorters = { alpha: (a, b) => a.get("path").localeCompare(b.get("path")), method: (a, b) => a.get("method").localeCompare(b.get("method")) }, - apisSorter: { + tagsSorter: { alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) } } From 1cdc4691f79ae1d32c3ad9c644893068cb3b17fa Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Thu, 13 Jul 2017 20:38:56 -0700 Subject: [PATCH 17/25] Add MDN link to Array.prototype.sort() documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d076f377..008b06b9 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL -tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see Array.prototype.sort() to know how sort function works). Default is the order determined by Swagger-UI. +tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to know how sort function works). Default is the order determined by Swagger-UI. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable From e6c8eb3c61043e708ac48ec4462f4823be63dc1b Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Thu, 13 Jul 2017 21:02:37 -0700 Subject: [PATCH 18/25] Pass tag names to tagsSorter instead of taggedOperations values --- src/core/plugins/spec/selectors.js | 12 +++++++----- src/core/utils.js | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index c9b31cf1..82056b7e 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -202,12 +202,14 @@ export const operationsWithTags = createSelector( export const taggedOperations = (state) => ({ getConfigs }) => { let { tagsSorter, operationsSorter } = getConfigs() - return operationsWithTags(state) - .sort((operationA, operationB) => { - let sortFn = (typeof tagsSorter === "function" ? tagsSorter : sorters.tagsSorter[ tagsSorter ]) - return (!sortFn ? null : sortFn(operationA, operationB)) - }) + .sortBy( + (val, key) => key, // get the name of the tag to be passed to the sorter + (tagA, tagB) => { + let sortFn = (typeof tagsSorter === "function" ? tagsSorter : sorters.tagsSorter[ tagsSorter ]) + return (!sortFn ? null : sortFn(tagA, tagB)) + } + ) .map((ops, tag) => { let sortFn = (typeof operationsSorter === "function" ? operationsSorter : sorters.operationsSorter[ operationsSorter ]) let operations = (!sortFn ? ops : ops.sort(sortFn)) diff --git a/src/core/utils.js b/src/core/utils.js index f4b925f6..677b8d90 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -576,7 +576,7 @@ export const sorters = { method: (a, b) => a.get("method").localeCompare(b.get("method")) }, tagsSorter: { - alpha: (a, b) => a.getIn([0, "operation", "tags", 0]).localeCompare(b.getIn([0, "operation", "tags", 0])) + alpha: (a, b) => a.localeCompare(b) } } From e2b73ebf2a65e583ab01f6d8ae81027fd5fe551b Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 13 Jul 2017 21:10:48 -0700 Subject: [PATCH 19/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c82e86d0..3ba6b44e 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url` validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. oauth2RedirectUrl | OAuth redirect URL -tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to know how sort function works). Default is the order determined by Swagger-UI. +tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. configUrl | Configs URL parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable From 28912dded3a330fb034a7a78361508c5d6f3deeb Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 13 Jul 2017 21:14:56 -0700 Subject: [PATCH 20/25] Update index.js --- src/core/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/index.js b/src/core/index.js index 23b206c6..fa5db888 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -17,7 +17,6 @@ const CONFIGS = [ "authorizations", "docExpansion", "tagsSorter", - "apisSorter", "maxDisplayedTags", "filter", "operationsSorter", From 8b5c2cc4096831f4e61a6a095bf7d917a1e56fb8 Mon Sep 17 00:00:00 2001 From: Minasokoni Date: Thu, 13 Jul 2017 21:48:20 -0700 Subject: [PATCH 21/25] moved filter search to layout --- src/core/components/layouts/base.jsx | 26 +++++++++++++++++++++++++- src/plugins/topbar/topbar.jsx | 4 ---- src/style/_layout.scss | 12 ++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index 3e6c7139..f90dd848 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -13,8 +13,13 @@ export default class BaseLayout extends React.Component { getComponent: PropTypes.func.isRequired } + onFilterChange =(e) => { + let {target: {value}} = e + this.props.layoutActions.updateFilter(value) + } + render() { - let { specSelectors, specActions, getComponent } = this.props + let { specSelectors, specActions, getComponent, layoutSelectors } = this.props let info = specSelectors.info() let url = specSelectors.url() @@ -31,6 +36,15 @@ export default class BaseLayout extends React.Component { let Row = getComponent("Row") let Col = getComponent("Col") let Errors = getComponent("errors", true) + + let isLoading = specSelectors.loadingStatus() === "loading" + let isFailed = specSelectors.loadingStatus() === "failed" + let filter = layoutSelectors.currentFilter() + + let inputStyle = {} + if(isFailed) inputStyle.color = "red" + if(isLoading) inputStyle.color = "#aaa" + const Schemes = getComponent("schemes") const isSpecEmpty = !specSelectors.specStr() @@ -57,6 +71,7 @@ export default class BaseLayout extends React.Component { { schemes && schemes.size ? ( ) : null } + { securityDefinitions ? ( ) : null } @@ -64,6 +79,15 @@ export default class BaseLayout extends React.Component {
    ) : null } + { + filter === null || filter === false ? null : +
    + + + +
    + } + diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index 314e1d4e..c764e54f 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -135,10 +135,6 @@ export default class Topbar extends React.Component { Swagger UX swagger - { - filter === null || filter === false ? null : - - }
    {control}
    diff --git a/src/style/_layout.scss b/src/style/_layout.scss index 78e09249..61efe855 100644 --- a/src/style/_layout.scss +++ b/src/style/_layout.scss @@ -327,6 +327,18 @@ body } } +.filter +{ + .operation-filter-input + { + width: 100%; + margin: 20px 0; + padding: 10px 10px; + + border: 2px solid #d8dde7; + } +} + .tab { From d7c28912e07f49ce16b0ff8a5073cca189b5f356 Mon Sep 17 00:00:00 2001 From: Minasokoni Date: Thu, 13 Jul 2017 21:50:19 -0700 Subject: [PATCH 22/25] updated input styling --- src/style/_topbar.scss | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/style/_topbar.scss b/src/style/_topbar.scss index b1427c78..d3b76aa6 100644 --- a/src/style/_topbar.scss +++ b/src/style/_topbar.scss @@ -29,12 +29,6 @@ padding: 0 10px; } } - .operation-filter-input - { - border: 2px solid #547f00; - border-right: none; - border-radius: 4px 0 0 4px; - } .download-url-wrapper { @@ -49,7 +43,6 @@ margin: 0; border: 2px solid #547f00; - border-radius: 0 0 0 0; outline: none; } From d698aef1cde3e574e3be81b228a50a2a333fec76 Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 13 Jul 2017 21:57:49 -0700 Subject: [PATCH 23/25] "Filter Operations" -> "Filter by tag" --- src/core/components/layouts/base.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index f90dd848..bbd7edbd 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -83,7 +83,7 @@ export default class BaseLayout extends React.Component { filter === null || filter === false ? null :
    - +
    } From 2ae61e85b8f673c85ea0e05b2d5a09978c6da288 Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 13 Jul 2017 22:00:16 -0700 Subject: [PATCH 24/25] Update base.jsx --- src/core/components/layouts/base.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx index bbd7edbd..f502b88f 100644 --- a/src/core/components/layouts/base.jsx +++ b/src/core/components/layouts/base.jsx @@ -83,7 +83,7 @@ export default class BaseLayout extends React.Component { filter === null || filter === false ? null :
    - +
    } From f916e3c208bcfb4e3a460f470f3d97ce2820fe56 Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 13 Jul 2017 22:19:17 -0700 Subject: [PATCH 25/25] Topbar: Remove unused `filter` and `layoutSelectors` --- src/plugins/topbar/topbar.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index c764e54f..fd3654bb 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -7,7 +7,6 @@ import Logo from "./logo_small.png" export default class Topbar extends React.Component { static propTypes = { - layoutSelectors: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired } @@ -91,13 +90,12 @@ export default class Topbar extends React.Component { } render() { - let { getComponent, specSelectors, getConfigs, layoutSelectors } = this.props + let { getComponent, specSelectors, getConfigs } = this.props const Button = getComponent("Button") const Link = getComponent("Link") let isLoading = specSelectors.loadingStatus() === "loading" let isFailed = specSelectors.loadingStatus() === "failed" - let filter = layoutSelectors.currentFilter() let inputStyle = {} if(isFailed) inputStyle.color = "red"