From d8400f872999c7ca50704e03ccd450f98ce25840 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Sun, 9 Jul 2017 14:17:18 -0600 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 cf12091d9323251e9b18ee5f46d3b9335942af1f Mon Sep 17 00:00:00 2001 From: Kyle Shockey Date: Tue, 11 Jul 2017 21:33:14 -0700 Subject: [PATCH 4/7] 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 5/7] 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 6/7] 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 7/7] 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({ })