From 0bc382b78a83ce9b145a72e02f26a3741d6d4848 Mon Sep 17 00:00:00 2001 From: TANAKA Koichi Date: Tue, 18 Jul 2017 16:52:29 +0900 Subject: [PATCH 1/9] Fix oauth2 password flow fix filed name for scope of grant request body. --- src/core/plugins/auth/actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/plugins/auth/actions.js b/src/core/plugins/auth/actions.js index 221d80a8..772e858c 100644 --- a/src/core/plugins/auth/actions.js +++ b/src/core/plugins/auth/actions.js @@ -73,7 +73,7 @@ export const authorizePassword = ( auth ) => ( { authActions } ) => { let { schema, name, username, password, passwordType, clientId, clientSecret } = auth let form = { grant_type: "password", - scopes: encodeURIComponent(auth.scopes.join(scopeSeparator)) + scope: encodeURIComponent(auth.scopes.join(scopeSeparator)) } let query = {} let headers = {} From c076a07092854ba66f07d5d47f3d3bb4ad47a8b7 Mon Sep 17 00:00:00 2001 From: Damiano Albani Date: Tue, 18 Jul 2017 15:23:44 +0200 Subject: [PATCH 2/9] Embellish "base URL" caption --- src/core/components/info.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/info.jsx b/src/core/components/info.jsx index 6ea1ed48..5e2b368a 100644 --- a/src/core/components/info.jsx +++ b/src/core/components/info.jsx @@ -15,7 +15,7 @@ class Path extends React.Component { return (
-        [ Base url: {host}{basePath}]
+        [ Base URL: {host}{basePath} ]
       
) } From 25c63b5f76128d177d59f932da0befe875d96598 Mon Sep 17 00:00:00 2001 From: Leon Weidauer Date: Thu, 20 Jul 2017 12:01:00 +0200 Subject: [PATCH 3/9] Fix length issue in OrderedMaps Previously, a definiton with a 'length' property with numeric value would result in an OrderedMap of that length. This is now fixed and covered by tests --- src/core/utils.js | 2 +- test/core/utils.js | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/core/utils.js b/src/core/utils.js index 95771fb4..f2e28948 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -41,7 +41,7 @@ export function fromJSOrdered (js) { return !isObject(js) ? js : Array.isArray(js) ? Im.Seq(js).map(fromJSOrdered).toList() : - Im.Seq(js).map(fromJSOrdered).toOrderedMap() + Im.OrderedMap(js).map(fromJSOrdered) } export function bindToState(obj, state) { diff --git a/test/core/utils.js b/test/core/utils.js index a63da13d..fbfb24ab 100644 --- a/test/core/utils.js +++ b/test/core/utils.js @@ -1,10 +1,10 @@ /* eslint-env mocha */ import expect from "expect" import { fromJS } from "immutable" -import { mapToList, validateNumber, validateInteger, validateParam, validateFile } from "core/utils" +import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils" import win from "core/window" -describe("utils", function(){ +describe("utils", function() { describe("mapToList", function(){ @@ -306,4 +306,31 @@ describe("utils", function(){ expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] ) }) }) + + describe("fromJSOrdered", () => { + it("should create an OrderedMap from an object", () => { + const param = { + value: "test" + } + + const result = fromJSOrdered(param).toJS() + expect( result ).toEqual( { value: "test" } ) + }) + + it("should not use an object's length property for Map size", () => { + const param = { + length: 5 + } + + const result = fromJSOrdered(param).toJS() + expect( result ).toEqual( { length: 5 } ) + }) + + it("should create an OrderedMap from an array", () => { + const param = [1, 1, 2, 3, 5, 8] + + const result = fromJSOrdered(param).toJS() + expect( result ).toEqual( [1, 1, 2, 3, 5, 8] ) + }) + }) }) From 1e5304790ede020e31fcedfdf34f165c715cf91a Mon Sep 17 00:00:00 2001 From: shockey Date: Thu, 20 Jul 2017 17:20:01 -0700 Subject: [PATCH 4/9] Enable deep linking in dist/index.html --- dist/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/index.html b/dist/index.html index f6aaf9e4..52590951 100644 --- a/dist/index.html +++ b/dist/index.html @@ -76,6 +76,7 @@ window.onload = function() { const ui = SwaggerUIBundle({ url: "http://petstore.swagger.io/v2/swagger.json", dom_id: '#swagger-ui', + deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset From 666e22f9895ec70095d4cf29ade8fd625b96b1fb Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Thu, 20 Jul 2017 21:33:57 -0600 Subject: [PATCH 5/9] Update parameter elements. Rework validateParam() function. Added .btn-sm class for "Add item" and "Remove item" buttons in array parameters. Reduce border-width on + ) @@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent { render() { let { getComponent, required, schema, fn } = this.props + let errors = schema.errors || [] let itemSchema = fn.inferSchema(schema.items) const JsonSchemaForm = getComponent("JsonSchemaForm") @@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent { if ( enumValue ) { const Select = getComponent("Select") - return () } } diff --git a/src/core/utils.js b/src/core/utils.js index 95771fb4..9e114dae 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -468,6 +468,18 @@ export const validateFile = ( val ) => { } } +export const validateBoolean = ( val ) => { + if ( !(val === "true" || val === "false" || val === true || val === false) ) { + return "Value must be a boolean" + } +} + +export const validateString = ( val ) => { + if ( val && typeof val !== "string" ) { + return "Value must be a string" + } +} + // validation of parameters before execute export const validateParam = (param, isXml) => { let errors = [] @@ -475,52 +487,66 @@ export const validateParam = (param, isXml) => { let required = param.get("required") let type = param.get("type") - let stringCheck = type === "string" && !value - let arrayCheck = type === "array" && Array.isArray(value) && !value.length - let listCheck = type === "array" && Im.List.isList(value) && !value.count() - let fileCheck = type === "file" && !(value instanceof win.File) + // If the parameter is required OR the parameter has a value (meaning optional, but filled in) + // then we should do our validation routine + if ( required || value ) { + // These checks should evaluate to true if the parameter's value is valid + let stringCheck = type === "string" && value && !validateString(value) + let arrayCheck = type === "array" && Array.isArray(value) && value.length + let listCheck = type === "array" && Im.List.isList(value) && value.count() + let fileCheck = type === "file" && value instanceof win.File + let booleanCheck = type === "boolean" && !validateBoolean(value) + let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number + let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer - if ( required && (stringCheck || arrayCheck || listCheck || fileCheck) ) { - errors.push("Required field is not provided") - return errors - } + if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) { + errors.push("Required field is not provided") + return errors + } - if ( value === null || value === undefined ) { - return errors - } + if ( type === "string" ) { + let err = validateString(value) + if (!err) return errors + errors.push(err) + } else if ( type === "boolean" ) { + let err = validateBoolean(value) + if (!err) return errors + errors.push(err) + } else if ( type === "number" ) { + let err = validateNumber(value) + if (!err) return errors + errors.push(err) + } else if ( type === "integer" ) { + let err = validateInteger(value) + if (!err) return errors + errors.push(err) + } else if ( type === "array" ) { + let itemType - if ( type === "number" ) { - let err = validateNumber(value) - if (!err) return errors - errors.push(err) - } else if ( type === "integer" ) { - let err = validateInteger(value) - if (!err) return errors - errors.push(err) - } else if ( type === "array" ) { - let itemType + if ( !value.count() ) { return errors } - if ( !value.count() ) { return errors } + itemType = param.getIn(["items", "type"]) - itemType = param.getIn(["items", "type"]) + value.forEach((item, index) => { + let err - value.forEach((item, index) => { - let err + if (itemType === "number") { + err = validateNumber(item) + } else if (itemType === "integer") { + err = validateInteger(item) + } else if (itemType === "string") { + err = validateString(item) + } - if (itemType === "number") { - err = validateNumber(item) - } else if (itemType === "integer") { - err = validateInteger(item) - } - - if ( err ) { - errors.push({ index: index, error: err}) - } - }) - } else if ( type === "file" ) { - let err = validateFile(value) - if (!err) return errors - errors.push(err) + if ( err ) { + errors.push({ index: index, error: err}) + } + }) + } else if ( type === "file" ) { + let err = validateFile(value) + if (!err) return errors + errors.push(err) + } } return errors diff --git a/src/style/_buttons.scss b/src/style/_buttons.scss index 2470f8b0..bfb85023 100644 --- a/src/style/_buttons.scss +++ b/src/style/_buttons.scss @@ -14,6 +14,11 @@ @include text_headline(); + &.btn-sm { + font-size: 12px; + padding: 4px 23px; + } + &[disabled] { cursor: not-allowed; @@ -165,6 +170,9 @@ button { cursor: pointer; - outline: none; + + &.invalid { + @include invalidFormElement(); + } } diff --git a/src/style/_form.scss b/src/style/_form.scss index 185b836e..e54d5438 100644 --- a/src/style/_form.scss +++ b/src/style/_form.scss @@ -21,6 +21,10 @@ select background: #f7f7f7; } + + &.invalid { + @include invalidFormElement(); + } } .opblock-body select @@ -53,12 +57,8 @@ input[type=file] border-radius: 4px; background: #fff; - &.invalid - { - animation: shake .4s 1; - - border-color: $_color-delete; - background: lighten($_color-delete, 35%); + &.invalid { + @include invalidFormElement(); } } diff --git a/src/style/_mixins.scss b/src/style/_mixins.scss index a2a27d48..8fd01720 100644 --- a/src/style/_mixins.scss +++ b/src/style/_mixins.scss @@ -166,3 +166,9 @@ $browser-context: 16; @warn 'Breakpoint mixin supports: tablet, mobile, desktop'; } } + +@mixin invalidFormElement() { + animation: shake .4s 1; + border-color: $_color-delete; + background: lighten($_color-delete, 35%); +} diff --git a/src/style/_table.scss b/src/style/_table.scss index 3d58f3d8..d1481709 100644 --- a/src/style/_table.scss +++ b/src/style/_table.scss @@ -97,6 +97,10 @@ table width: 100%; max-width: 340px; } + + select { + border-width: 1px; + } } .parameter__name diff --git a/test/core/utils.js b/test/core/utils.js index a63da13d..65ed7435 100644 --- a/test/core/utils.js +++ b/test/core/utils.js @@ -176,6 +176,7 @@ describe("utils", function(){ let result = null it("validates required strings", function() { + // invalid string param = fromJS({ required: true, type: "string", @@ -183,9 +184,39 @@ describe("utils", function(){ }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + + // valid string + param = fromJS({ + required: true, + type: "string", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional strings", function() { + // valid (empty) string + param = fromJS({ + required: false, + type: "string", + value: "" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid string + param = fromJS({ + required: false, + type: "string", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) it("validates required files", function() { + // invalid file param = fromJS({ required: true, type: "file", @@ -193,9 +224,48 @@ describe("utils", function(){ }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + + // valid file + param = fromJS({ + required: true, + type: "file", + value: new win.File() + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional files", function() { + // invalid file + param = fromJS({ + required: false, + type: "file", + value: "not a file" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a file"] ) + + // valid (empty) file + param = fromJS({ + required: false, + type: "file", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid file + param = fromJS({ + required: false, + type: "file", + value: new win.File() + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) it("validates required arrays", function() { + // invalid (empty) array param = fromJS({ required: true, type: "array", @@ -204,75 +274,51 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + // invalid (not an array) param = fromJS({ required: true, type: "array", - value: [] + value: undefined }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) - }) - it("validates numbers", function() { - // string instead of a number + // invalid array, items do not match correct type param = fromJS({ - required: false, - type: "number", - value: "test" + required: true, + type: "array", + value: [1], + items: { + type: "string" + } }) result = validateParam( param, false ) - expect( result ).toEqual( ["Value must be a number"] ) + expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] ) - // undefined value + // valid array, with no 'type' for items param = fromJS({ - required: false, - type: "number", - value: undefined + required: true, + type: "array", + value: ["1"] }) result = validateParam( param, false ) expect( result ).toEqual( [] ) - // null value + // valid array, items match type param = fromJS({ - required: false, - type: "number", - value: null + required: true, + type: "array", + value: ["1"], + items: { + type: "string" + } }) result = validateParam( param, false ) expect( result ).toEqual( [] ) }) - it("validates integers", function() { - // string instead of integer - param = fromJS({ - required: false, - type: "integer", - value: "test" - }) - result = validateParam( param, false ) - expect( result ).toEqual( ["Value must be an integer"] ) - - // undefined value - param = fromJS({ - required: false, - type: "integer", - value: undefined - }) - result = validateParam( param, false ) - expect( result ).toEqual( [] ) - - // null value - param = fromJS({ - required: false, - type: "integer", - value: null - }) - result = validateParam( param, false ) - expect( result ).toEqual( [] ) - }) - - it("validates arrays", function() { - // empty array + it("validates optional arrays", function() { + // valid, empty array param = fromJS({ required: false, type: "array", @@ -281,7 +327,7 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( [] ) - // numbers + // invalid, items do not match correct type param = fromJS({ required: false, type: "array", @@ -293,17 +339,209 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] ) - // integers + // valid param = fromJS({ required: false, type: "array", - value: ["not", "numbers"], + value: ["test"], items: { - type: "integer" + type: "string" } }) result = validateParam( param, false ) - expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] ) + expect( result ).toEqual( [] ) + }) + + it("validates required booleans", function() { + // invalid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid boolean value (not a boolean) + param = fromJS({ + required: true, + type: "boolean", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: "true" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: false + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional booleans", function() { + // valid (empty) boolean value + param = fromJS({ + required: false, + type: "boolean", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // invalid boolean value (not a boolean) + param = fromJS({ + required: false, + type: "boolean", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a boolean"] ) + + // valid boolean value + param = fromJS({ + required: false, + type: "boolean", + value: "true" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid boolean value + param = fromJS({ + required: false, + type: "boolean", + value: false + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates required numbers", function() { + // invalid number, string instead of a number + param = fromJS({ + required: true, + type: "number", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid number, undefined value + param = fromJS({ + required: true, + type: "number", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid number + param = fromJS({ + required: true, + type: "number", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional numbers", function() { + // invalid number, string instead of a number + param = fromJS({ + required: false, + type: "number", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a number"] ) + + // valid (empty) number + param = fromJS({ + required: false, + type: "number", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid number + param = fromJS({ + required: false, + type: "number", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates required integers", function() { + // invalid integer, string instead of an integer + param = fromJS({ + required: true, + type: "integer", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid integer, undefined value + param = fromJS({ + required: true, + type: "integer", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid integer + param = fromJS({ + required: true, + type: "integer", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional integers", function() { + // invalid integer, string instead of an integer + param = fromJS({ + required: false, + type: "integer", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be an integer"] ) + + // valid (empty) integer + param = fromJS({ + required: false, + type: "integer", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid number + param = fromJS({ + required: false, + type: "integer", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) }) }) From c82f85f1234cf6fd0c08a161c056e865c9780e1c Mon Sep 17 00:00:00 2001 From: shockey Date: Fri, 21 Jul 2017 16:01:52 -0700 Subject: [PATCH 6/9] Update topbar.jsx --- src/plugins/topbar/topbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/topbar/topbar.jsx b/src/plugins/topbar/topbar.jsx index fd3654bb..ec9db730 100644 --- a/src/plugins/topbar/topbar.jsx +++ b/src/plugins/topbar/topbar.jsx @@ -130,7 +130,7 @@ export default class Topbar extends React.Component {
- Swagger UX + Swagger UI swagger
From 0010bf20a62f37d8284211471d37c3936df10606 Mon Sep 17 00:00:00 2001 From: shockey Date: Fri, 21 Jul 2017 16:04:58 -0700 Subject: [PATCH 7/9] Update add-plugin.md --- src/plugins/add-plugin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/add-plugin.md b/src/plugins/add-plugin.md index 7a77cb30..2e2d52e1 100644 --- a/src/plugins/add-plugin.md +++ b/src/plugins/add-plugin.md @@ -20,7 +20,7 @@ SwaggerUI({ }) ``` -Or if you're updating the core plugins.. you'll add it to [src/js/bootstrap-plugin](https://github.com/SmartBear/swagger-ux/blob/master/src/js/bootstrap-plugin.js) +Or if you're updating the core plugins.. you'll add it to the base preset: [src/core/presets/base.js](https://github.com/swagger-api/swagger-ui/blob/master/src/core/presets/base.js) Each Plugin is a function that returns an object. That object will get merged with the `system` and later bound to the state. Here is an example of each `type` From eb1f3b1fa613d68e18c965d1cb48d6f886d01f39 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Fri, 21 Jul 2017 17:23:28 -0600 Subject: [PATCH 8/9] Fixes #3422 - Fixed regression bug on models.jsx expand/collapse arrows due to bad merge --- src/core/components/models.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/components/models.jsx b/src/core/components/models.jsx index c61ae0c9..86c3256d 100644 --- a/src/core/components/models.jsx +++ b/src/core/components/models.jsx @@ -24,8 +24,8 @@ export default class Models extends Component { return

layoutActions.show("models", !showModels)}> Models - - + +

From b9bb4c124ec76bc3e565344c8abb5ce26432e9f6 Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Fri, 21 Jul 2017 18:46:50 -0600 Subject: [PATCH 9/9] Fixes #3434 - Change link style color for .response-col_description__inner links --- src/style/_layout.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/style/_layout.scss b/src/style/_layout.scss index 90b9a088..43000ec6 100644 --- a/src/style/_layout.scss +++ b/src/style/_layout.scss @@ -508,6 +508,15 @@ body { margin: 0; } + + a + { + @include text_code(#89bf04); + text-decoration: underline; + &:hover { + color: #81b10c; + } + } } }