Compare commits

...
87 Commits
Author SHA1 Message Date
kyle 774a06606d Merge pull request #3699 from shockey/v/3.2.2
v3.2.2
2017-09-23 14:43:44 -07:00
Kyle Shockey 2d10a740af Rebuild with changes from #3702 2017-09-23 13:09:08 -07:00
Kyle Shockey 45e7a54182 Merge branch 'master' of github.com:swagger-api/swagger-ui into v/3.2.2 2017-09-23 12:58:06 -07:00
kyle 9e418ad68b Merge pull request #3702 from owenconti/bug/3511-query-formData-parameters
Fixes #3511 - 2nd attempt - Query & formData parameters together
2017-09-23 12:57:35 -07:00
Kyle Shockey de61dccff0 Revert "Revert "Merge pull request #3516 from owenconti/bug/3511-query-formData-parameters""
This reverts commit beeb6b608e.
2017-09-23 12:54:17 -07:00
Owen Conti fd00a0489a Remove shouldComponentUpdate from parameter-row component. It will be put back in eventually as part of the performance optimizations once the parameter components are converted to the smart/dumb approach. 2017-09-23 13:10:09 -06:00
Kyle Shockey beeb6b608e Revert "Merge pull request #3516 from owenconti/bug/3511-query-formData-parameters"
This reverts commit 6a7e9d2e88, reversing
changes made to eb01beedfa.
2017-09-23 10:51:32 -07:00
Kyle Shockey c8a9ddbf94 v3.2.2 2017-09-23 00:02:10 -07:00
kyle 1de6010629 Merge pull request #3666 from AlexanderVangelov/master
OAuth2 authorizationUrl allow extra query parameters ('&' vs '?')
2017-09-22 20:49:21 -07:00
kyle b6eb23217f Merge branch 'master' into master 2017-09-22 20:45:07 -07:00
kyle a3f923eec7 Merge pull request #3698 from shockey/heldersepu-master
Heldersepu master
2017-09-22 20:16:08 -07:00
Kyle Shockey 6b59707af1 Fix tests 2017-09-22 19:50:36 -07:00
kyle 827bcd2f36 Merge branch 'master' into master 2017-09-22 19:50:19 -07:00
kyle 6a7e9d2e88 Merge pull request #3516 from owenconti/bug/3511-query-formData-parameters
Fixes #3511 - Query & formData parameters together
2017-09-22 19:27:31 -07:00
HelderSepu e08f31d674 Add UnitTests for validateDateTime & validateGuid 2017-09-22 21:37:33 -04:00
HelderSepu 7d9b56255c Correction to the validateDateTime 2017-09-22 17:44:01 -04:00
Helder Sepulveda b2abf769de Merge branch 'master' into master 2017-09-22 13:04:09 -04:00
HelderSepu 11768b16bf Correct IF for validateDateTime & validateGuid 2017-09-22 11:30:07 -04:00
kyle 54a2d402c6 Merge branch 'master' into master 2017-09-21 00:15:41 -07:00
Owen Conti a1758da87c Merge branch 'master' into bug/3511-query-formData-parameters 2017-09-20 22:37:43 -06:00
kyle eb01beedfa Merge pull request #3691 from shockey/bug/3638-61338ref-in-examples
Remove $$ref values from response examples
2017-09-20 17:42:03 -07:00
kyle deebe1f840 Merge branch 'master' into bug/3638-61338ref-in-examples 2017-09-20 17:36:57 -07:00
Kyle Shockey 69941a6d9a Remove $$ref values from response examples 2017-09-20 17:34:23 -07:00
kyle 6a8f821901 Merge pull request #3690 from shockey/bug/3636-tag-description-markdown
Display Tag descriptions as Markdown
2017-09-20 17:01:45 -07:00
Kyle Shockey b0a580bdc1 Display Tag descriptions as Markdown 2017-09-20 16:55:45 -07:00
Alexander Vangelov 696bdcf961 Merge branch 'master' into master 2017-09-20 13:11:53 -04:00
kyle 6d67c6dabe Merge pull request #3676 from owenconti/bug/3633-primitive-titles
Fixes #3633 - PrimitiveModel titles
2017-09-19 20:17:49 -07:00
kyle 69799b0975 Merge branch 'master' into bug/3633-primitive-titles 2017-09-19 20:14:00 -07:00
HelderSepu 85b7b7241d Add validateDateTime & validateGuid
Initial work to tacke some of the missing validation (Issue #993)
2017-09-19 14:31:27 -04:00
HelderSepu bd6e482df2 Merge remote-tracking branch 'refs/remotes/swagger-api/master' 2017-09-19 13:37:04 -04:00
Owen Conti 7ef8a7ddc7 Merge branch 'master' of github.com:swagger-api/swagger-ui into bug/3511-query-formData-parameters
# Conflicts:
#	src/core/components/parameter-row.jsx
#	src/core/plugins/spec/actions.js
2017-09-18 16:59:08 -06:00
Kyle aa9e008f0b Merge pull request #3679 from swagger-api/shockey-readme-updates
README: npm module clarifications
2017-09-18 15:12:25 -07:00
Kyle b43ac6da44 Update README.md 2017-09-18 13:38:11 -07:00
Kyle cb3e1ed78c Update README.md 2017-09-18 13:36:07 -07:00
Owen Conti 44ece46cd3 Fixes #3633
Make sure PrimitiveModel uses the schema's title first and then falls back to the passed-in `name` property. Added enzyme test for functionality.
2017-09-17 09:49:13 -06:00
Owen Conti f63f022e0c Remove .only from utils test 2017-09-17 09:48:26 -06:00
Owen Conti b855c25406 Slightly increase size available for property names. Change units to em and add a margin to separate the property name from the property type. 2017-09-17 09:48:03 -06:00
Owen Conti 08282205aa Fix property key: value alignment in array-model 2017-09-17 09:45:33 -06:00
Alexander Vangelov 90fa7065f8 Merge branch 'master' into master 2017-09-16 11:24:36 -04:00
Kyle aee5e75913 Merge pull request #3673 from shockey/v/3.2.1
v3.2.1
2017-09-15 21:22:37 -07:00
Kyle Shockey a625177c38 v3.2.1 2017-09-15 21:15:21 -07:00
Kyle a777e9ba91 Merge pull request #3669 from shockey/bug/oas3-accept-controls
OAS3: Accept header control
2017-09-15 20:38:05 -07:00
Kyle Shockey ae5ad484d9 More merge oversights... 2017-09-15 20:33:16 -07:00
Kyle Shockey 6010245210 Roll back win import removal
Lost in merge conflict....
2017-09-15 20:29:49 -07:00
Kyle bd5424308f Merge branch 'master' into bug/oas3-accept-controls 2017-09-15 20:21:27 -07:00
Kyle ef5904f3f0 Merge pull request #3668 from owenconti/test/3667-escaping-utils-tests
Deep link path util tests
2017-09-15 20:19:28 -07:00
Kyle Shockey ef8b37a580 LINTING! 2017-09-15 20:17:35 -07:00
Kyle fa312cb70d Merge branch 'master' into bug/oas3-accept-controls 2017-09-15 20:11:20 -07:00
AlexVangelov c1abdfb1c4 follow lowercase naming convention in tests 2017-09-15 21:04:38 -04:00
AlexVangelov 5bf6d2ff0b Merge branches 'master' and 'master' of github.com:AlexanderVangelov/swagger-ui 2017-09-15 20:53:52 -04:00
AlexVangelov 4172e33e04 satisfy project lint rules 2017-09-15 20:52:55 -04:00
Alexander Vangelov 34e8fffb65 Merge branch 'master' into master 2017-09-15 20:40:46 -04:00
Owen Conti 33ee880f36 Add extra check for String types in createDeepLinkPath. Add trim() call on passed-in value in createDeepLinkPath. Added unit tests for new deep link util functions. 2017-09-15 17:17:45 -06:00
Owen Conti acac3ee875 Merge branch 'master' of github.com:swagger-api/swagger-ui 2017-09-15 16:51:10 -06:00
Kyle 11d8a341e7 Merge pull request #3661 from owenconti/bug/3596-permalink-encoding
Fixes #3596 - Deep linking issue with spaces
2017-09-15 14:49:22 -07:00
AlexVangelov 9b1a6141df OAuth2 authorizationUrl with extra query parameters (should include double '?') 2017-09-15 15:57:41 -04:00
Owen Conti 78ed1e60f3 Merge branch 'master' of github.com:swagger-api/swagger-ui 2017-09-14 14:20:10 -06:00
Owen Conti 840912cb56 Handle null value in createDeepLinkPath 2017-09-13 21:38:07 -06:00
Owen Conti a6e070ac76 Replace spaces with underscores when setting the hash value and inserting the ID into the DOM. Escape the deep link path when querying for the DOM element on hash change. 2017-09-13 21:32:46 -06:00
Owen Conti 16364fb81e Merge branch 'master' of github.com:swagger-api/swagger-ui into bug/3596-permalink-encoding 2017-09-13 17:25:38 -06:00
Owen Conti 430e2a970f Fixes #3596
Wrap `isShownKey` values in a function that replaces spaces with underscores. When parsing the hash on route change, replace the spaces in the values with underscores again.
2017-09-13 17:20:37 -06:00
Kyle c7cb902eee Merge pull request #3655 from owenconti/bug/3032-wrong-properties-order
Fixes #3032 - Wrong property order
2017-09-13 12:21:20 -07:00
Owen Conti ef99b7e434 Remove it.only from new test 2017-09-12 23:09:21 -06:00
Owen Conti cade5100e0 Merge branch 'master' of github.com:swagger-api/swagger-ui into bug/3032-wrong-properties-order 2017-09-12 23:07:36 -06:00
Owen Conti cb88cd53b6 Added test for response.jsx to make sure properties are passed to ModelExample component in the correct order 2017-09-12 23:07:11 -06:00
Owen Conti a47cc284f7 Update response.jsx to use already existing, fromJSOrdered function 2017-09-12 23:06:24 -06:00
Kyle Shockey 277cc81a8c OAS3 Accept header control: State-side 2017-09-12 19:39:52 -07:00
Kyle Shockey 26edaa5f0b OAS3 Accept header control: Component-side 2017-09-12 17:22:51 -07:00
Owen Conti 7cd42992f2 Merge branch 'master' of github.com:swagger-api/swagger-ui 2017-09-12 17:14:39 -06:00
Kyle 746e247834 Merge pull request #3650 from owenconti/bug/3490-anyOf-oneOf-not
Fixes #3490 (mostly)
2017-09-11 19:59:00 -07:00
Kyle 8a4d2461d8 Merge branch 'master' into bug/3490-anyOf-oneOf-not 2017-09-11 19:54:59 -07:00
Kyle 72f01b631e Merge branch 'master' into bug/3032-wrong-properties-order 2017-09-11 19:51:02 -07:00
Owen Conti 408e038b2d fromJS does not maintain order of object properties. Use a reviver function with fromJS inside the response.jsx component for the passed down schema prop. 2017-09-11 20:28:58 -06:00
Ron 65ff161c0b Merge pull request #3579 from OpenGov/bug/SWAGGER_JSON-doc-fix
Updated docs for correct usage of SWAGGER_JSON
2017-09-11 05:25:16 -07:00
Ron 93fcf06620 Merge branch 'master' into bug/SWAGGER_JSON-doc-fix 2017-09-11 05:21:10 -07:00
Owen Conti 3f04d2dfc6 Merge branch 'master' into bug/3490-anyOf-oneOf-not 2017-09-09 13:56:22 -06:00
Owen Conti 12c96e3190 Add comment to array-model for to clarify change. Rework logic in Model.render() to fix bug with overriding name and schema from $ref definition. 2017-09-09 13:51:09 -06:00
Owen Conti e9f46e6f5e Working on refactoring of model.jsx 2017-09-08 17:59:41 -06:00
Owen Conti 3b9940567b Fix property names being displayed in array models 2017-09-07 18:28:38 -06:00
Matthew Seal 54b383a7d2 Updated docs for correct usage of SWAGGER_JSON 2017-08-15 18:02:17 -07:00
Owen Conti 5d7d20ec5e Merge branch 'master' into bug/3511-query-formData-parameters 2017-08-03 19:30:50 -06:00
Owen Conti 7a694e287a Change name format to in.name and update tests 2017-08-03 19:29:49 -06:00
Owen Conti 17e99428c7 Merge branch 'bug/3511-query-formData-parameters' of github.com:owenconti/swagger-ui into bug/3511-query-formData-parameters 2017-08-03 07:14:15 -06:00
Owen Conti ce8adb91a5 Fix failing selector test 2017-08-03 07:14:03 -06:00
Owen Conti 053d032e94 Merge branch 'master' into bug/3511-query-formData-parameters 2017-08-02 22:37:49 -06:00
Owen Conti 51016c33f4 Attach in value to parameters map so parameters with the same name from different in types do not override each other. 2017-08-02 22:37:31 -06:00
Owen Conti fdb0d13089 Fixes #3511 - Update changeParameter calls to accept in value to identify parameters based on name plus in value 2017-08-02 22:07:48 -06:00
37 changed files with 579 additions and 104 deletions
+5 -5
View File
@@ -10,10 +10,10 @@
As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details. As a brand new version, written from the ground up, there are some known issues and unimplemented features. Check out the [Known Issues](#known-issues) section for more details.
This repo publishes to two different NPM packages: This repository publishes to two different NPM modules:
* [swagger-ui](https://www.npmjs.com/package/swagger-ui) is intended for use as a node module. * [swagger-ui](https://www.npmjs.com/package/swagger-ui) is a traditional npm module intended for use in JavaScript web application projects that are capable of resolving dependencies (via Webpack, Browserify, etc).
* [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) comes pre-bundled with all dependencies and can be incorporated directly in a webapp. * [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) is a dependency-free module that includes everything you need to serve Swagger-UI in a server-side project, or a web project that can't resolve npm module dependencies.
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x). For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | ----- ------------------ | ------------ | -------------------------- | -----
3.2.0 | 2017-09-08 | 2.0, 3.0 | [tag v3.2.0](https://github.com/swagger-api/swagger-ui/tree/v3.2.0) 3.2.2 | 2017-09-22 | 2.0, 3.0 | [tag v3.2.2](https://github.com/swagger-api/swagger-ui/tree/v3.2.2)
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21) 3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10) 2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) 2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
@@ -46,7 +46,7 @@ Will start nginx with swagger-ui on port 80.
Or you can provide your own swagger.json on your host Or you can provide your own swagger.json on your host
``` ```
docker run -p 80:8080 -e "SWAGGER_JSON=/foo/swagger.json" -v /bar:/foo swaggerapi/swagger-ui docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /bar:/foo swaggerapi/swagger-ui
``` ```
##### Prerequisites ##### Prerequisites
+16 -11
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAu7LA;;;;;;AA65DA;;;;;;;;;;;;;;;;;;;;;;;;;;AA68TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AA69pBA;;;;;AA81QA;AAm4DA;;;;;;AAo4YA;;;;;;AA0iaA;AA4lvBA","sourceRoot":""} {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AA4kMA;;;;;;AA65DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAq9TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAo/pBA;;;;;AAk6QA;;;;;AAynBA;AAi0CA;;;;;;AAq/YA;;;;;;AAojaA;AA8lvBA","sourceRoot":""}
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAokeA","sourceRoot":""} {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAkzeA","sourceRoot":""}
+4 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.2.0", "version": "3.2.2",
"main": "dist/swagger-ui.js", "main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git", "repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [ "contributors": [
@@ -41,6 +41,8 @@
"dependencies": { "dependencies": {
"base64-js": "^1.2.0", "base64-js": "^1.2.0",
"brace": "0.7.0", "brace": "0.7.0",
"classnames": "^2.2.5",
"css.escape": "1.5.1",
"deep-extend": "0.4.1", "deep-extend": "0.4.1",
"expect": "1.20.2", "expect": "1.20.2",
"getbase": "^2.8.2", "getbase": "^2.8.2",
@@ -75,7 +77,7 @@
"scroll-to-element": "^2.0.0", "scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0", "serialize-error": "2.0.0",
"shallowequal": "0.2.2", "shallowequal": "0.2.2",
"swagger-client": "3.1.0", "swagger-client": "^3.1.2",
"url-parse": "^1.1.8", "url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1", "whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1", "worker-loader": "^0.7.1",
+7 -2
View File
@@ -28,15 +28,20 @@ export default class ArrayModel extends Component {
<span className="model-title__text">{ title }</span> <span className="model-title__text">{ title }</span>
</span> </span>
/*
Note: we set `name={null}` in <Model> below because we don't want
the name of the current Model passed (and displayed) as the name of the array element Model
*/
return <span className="model"> return <span className="model">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]"> <ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
[ [
<span><Model { ...this.props } schema={ items } required={ false } depth={ depth + 1 } /></span> <span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
] ]
{ {
properties.size ? <span> properties.size ? <span>
{ properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}> { properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}>
<br />{ `${key}:`}{ String(v) }</span>) <br />{ key }: { String(v) }</span>)
}<br /></span> }<br /></span>
: null : null
} }
+26 -26
View File
@@ -30,39 +30,38 @@ export default class Model extends Component {
render () { render () {
let { getComponent, specSelectors, schema, required, name, isRef } = this.props let { getComponent, specSelectors, schema, required, name, isRef } = this.props
let ObjectModel = getComponent("ObjectModel") const ObjectModel = getComponent("ObjectModel")
let ArrayModel = getComponent("ArrayModel") const ArrayModel = getComponent("ArrayModel")
let PrimitiveModel = getComponent("PrimitiveModel") const PrimitiveModel = getComponent("PrimitiveModel")
let type = "object"
let $$ref = schema && schema.get("$$ref") let $$ref = schema && schema.get("$$ref")
let modelName = $$ref && this.getModelName( $$ref )
let modelSchema, type // If we weren't passed a `name` but have a ref, grab the name from the ref
if ( !name && $$ref ) {
name = this.getModelName( $$ref )
}
// If we weren't passed a `schema` but have a ref, grab the schema from the ref
if ( !schema && $$ref ) {
schema = this.getRefSchema( name )
}
const deprecated = specSelectors.isOAS3() && schema.get("deprecated") const deprecated = specSelectors.isOAS3() && schema.get("deprecated")
isRef = isRef !== undefined ? isRef : !!$$ref
if ( schema && (schema.get("type") || schema.get("properties")) ) { type = schema && schema.get("type") || type
modelSchema = schema
} else if ( $$ref ) {
modelSchema = this.getRefSchema( modelName )
}
type = modelSchema && modelSchema.get("type")
if ( !type && modelSchema && modelSchema.get("properties") ) {
type = "object"
}
switch(type) { switch(type) {
case "object": case "object":
return <ObjectModel return <ObjectModel
className="object" { ...this.props } className="object" { ...this.props }
schema={ modelSchema } schema={ schema }
name={ modelName || name } name={ name }
deprecated={deprecated} deprecated={deprecated}
isRef={ isRef!== undefined ? isRef : !!$$ref } /> isRef={ isRef } />
case "array": case "array":
return <ArrayModel return <ArrayModel
className="array" { ...this.props } className="array" { ...this.props }
schema={ modelSchema } schema={ schema }
name={ modelName || name } name={ name }
deprecated={deprecated} deprecated={deprecated}
required={ required } /> required={ required } />
case "string": case "string":
@@ -73,9 +72,10 @@ export default class Model extends Component {
return <PrimitiveModel return <PrimitiveModel
{ ...this.props } { ...this.props }
getComponent={ getComponent } getComponent={ getComponent }
schema={ modelSchema } schema={ schema }
name={ modelName || name } name={ name }
deprecated={deprecated} deprecated={deprecated}
required={ required }/> } required={ required }/>
}
} }
} }
-1
View File
@@ -34,7 +34,6 @@ export default class Models extends Component {
return <div className="model-container" key={ `models-section-${name}` }> return <div className="model-container" key={ `models-section-${name}` }>
<ModelWrapper name={ name } <ModelWrapper name={ name }
schema={ model } schema={ model }
isRef={ true }
getComponent={ getComponent } getComponent={ getComponent }
specSelectors={ specSelectors }/> specSelectors={ specSelectors }/>
</div> </div>
+4 -1
View File
@@ -28,6 +28,7 @@ export default class Operation extends PureComponent {
authSelectors: PropTypes.object, authSelectors: PropTypes.object,
specActions: PropTypes.object.isRequired, specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired, fn: PropTypes.object.isRequired,
@@ -117,7 +118,8 @@ export default class Operation extends PureComponent {
specSelectors, specSelectors,
authActions, authActions,
authSelectors, authSelectors,
getConfigs getConfigs,
oas3Actions
} = this.props } = this.props
let summary = operation.get("summary") let summary = operation.get("summary")
@@ -265,6 +267,7 @@ export default class Operation extends PureComponent {
getComponent={ getComponent } getComponent={ getComponent }
getConfigs={ getConfigs } getConfigs={ getConfigs }
specSelectors={ specSelectors } specSelectors={ specSelectors }
oas3Actions={oas3Actions}
specActions={ specActions } specActions={ specActions }
produces={ produces } produces={ produces }
producesValue={ operation.get("produces_value") } producesValue={ operation.get("produces_value") }
+9 -4
View File
@@ -1,7 +1,7 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { helpers } from "swagger-client" import { helpers } from "swagger-client"
import { createDeepLinkPath } from "core/utils"
const { opId } = helpers const { opId } = helpers
export default class Operations extends React.Component { export default class Operations extends React.Component {
@@ -9,6 +9,7 @@ export default class Operations extends React.Component {
static propTypes = { static propTypes = {
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired, specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired, layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired, layoutActions: PropTypes.object.isRequired,
@@ -21,6 +22,7 @@ export default class Operations extends React.Component {
let { let {
specSelectors, specSelectors,
specActions, specActions,
oas3Actions,
getComponent, getComponent,
layoutSelectors, layoutSelectors,
layoutActions, layoutActions,
@@ -34,6 +36,7 @@ export default class Operations extends React.Component {
const Operation = getComponent("operation") const Operation = getComponent("operation")
const Collapse = getComponent("Collapse") const Collapse = getComponent("Collapse")
const Markdown = getComponent("Markdown")
let showSummary = layoutSelectors.showSummary() let showSummary = layoutSelectors.showSummary()
let { let {
@@ -69,7 +72,7 @@ export default class Operations extends React.Component {
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"]) let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"]) let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
let isShownKey = ["operations-tag", tag] let isShownKey = ["operations-tag", createDeepLinkPath(tag)]
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list") let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
return ( return (
@@ -87,7 +90,7 @@ export default class Operations extends React.Component {
</a> </a>
{ !tagDescription ? null : { !tagDescription ? null :
<small> <small>
{ tagDescription } <Markdown source={tagDescription} />
</small> </small>
} }
@@ -124,7 +127,7 @@ export default class Operations extends React.Component {
const operationId = const operationId =
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id") op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
const isShownKey = ["operations", tag, operationId] const isShownKey = ["operations", createDeepLinkPath(tag), createDeepLinkPath(operationId)]
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method")) const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
const response = specSelectors.responseFor(op.get("path"), op.get("method")) const response = specSelectors.responseFor(op.get("path"), op.get("method"))
@@ -147,6 +150,8 @@ export default class Operations extends React.Component {
specActions={ specActions } specActions={ specActions }
specSelectors={ specSelectors } specSelectors={ specSelectors }
oas3Actions={oas3Actions}
layoutActions={ layoutActions } layoutActions={ layoutActions }
layoutSelectors={ layoutSelectors } layoutSelectors={ layoutSelectors }
+2 -2
View File
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
updateValues = (props) => { updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props let { specSelectors, pathMethod, param, isExecute, consumesValue="" } = props
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : {} let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : {}
let isXml = /xml/i.test(consumesValue) let isXml = /xml/i.test(consumesValue)
let isJson = /json/i.test(consumesValue) let isJson = /json/i.test(consumesValue)
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value") let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
@@ -107,7 +107,7 @@ export default class ParamBody extends PureComponent {
const HighlightCode = getComponent("highlightCode") const HighlightCode = getComponent("highlightCode")
const ContentType = getComponent("contentType") const ContentType = getComponent("contentType")
// for domains where specSelectors not passed // for domains where specSelectors not passed
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : param let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name"), param.get("in")) : param
let errors = parameter.get("errors", List()) let errors = parameter.get("errors", List())
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType") let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
+3 -4
View File
@@ -19,7 +19,7 @@ export default class ParameterRow extends Component {
let { specSelectors, pathMethod, param } = props let { specSelectors, pathMethod, param } = props
let defaultValue = param.get("default") let defaultValue = param.get("default")
let parameter = specSelectors.getParameter(pathMethod, param.get("name")) let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : "" let value = parameter ? parameter.get("value") : ""
if ( defaultValue !== undefined && value === undefined ) { if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue) this.onChangeWrapper(defaultValue)
@@ -81,13 +81,12 @@ export default class ParameterRow extends Component {
const Markdown = getComponent("Markdown") const Markdown = getComponent("Markdown")
let schema = param.get("schema") let schema = param.get("schema")
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type") let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
let isFormData = inType === "formData" let isFormData = inType === "formData"
let isFormDataSupported = "FormData" in win let isFormDataSupported = "FormData" in win
let required = param.get("required") let required = param.get("required")
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"]) let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
let parameter = specSelectors.getParameter(pathMethod, param.get("name")) let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : "" let value = parameter ? parameter.get("value") : ""
return ( return (
+2 -2
View File
@@ -37,7 +37,7 @@ export default class Parameters extends Component {
onChangeKey, onChangeKey,
} = this.props } = this.props
changeParam( onChangeKey, param.get("name"), value, isXml) changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
} }
onChangeConsumesWrapper = ( val ) => { onChangeConsumesWrapper = ( val ) => {
@@ -94,7 +94,7 @@ export default class Parameters extends Component {
<ParameterRow fn={ fn } <ParameterRow fn={ fn }
getComponent={ getComponent } getComponent={ getComponent }
param={ parameter } param={ parameter }
key={ parameter.get( "name" ) } key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
onChange={ this.onChange } onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper} onChangeConsumes={this.onChangeConsumesWrapper}
specSelectors={ specSelectors } specSelectors={ specSelectors }
+2 -1
View File
@@ -23,6 +23,7 @@ export default class Primitive extends Component {
let format = schema.get("format") let format = schema.get("format")
let xml = schema.get("xml") let xml = schema.get("xml")
let enumArray = schema.get("enum") let enumArray = schema.get("enum")
let title = schema.get("title") || name
let description = schema.get("description") let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 ) let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
const Markdown = getComponent("Markdown") const Markdown = getComponent("Markdown")
@@ -30,7 +31,7 @@ export default class Primitive extends Component {
return <span className="model"> return <span className="model">
<span className="prop"> <span className="prop">
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ name }</span> } { name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ title }</span> }
<span className="prop-type">{ type }</span> <span className="prop-type">{ type }</span>
{ format && <span className="prop-format">(${format})</span>} { format && <span className="prop-format">(${format})</span>}
{ {
+38 -10
View File
@@ -1,7 +1,8 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import cx from "classnames"
import { fromJS, Seq } from "immutable" import { fromJS, Seq } from "immutable"
import { getSampleSchema } from "core/utils" import { getSampleSchema, fromJSOrdered } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => { const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
if ( examples && examples.size ) { if ( examples && examples.size ) {
@@ -46,23 +47,35 @@ export default class Response extends React.Component {
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired, fn: PropTypes.object.isRequired,
contentType: PropTypes.string contentType: PropTypes.string,
controlsAcceptHeader: PropTypes.bool,
onContentTypeChange: PropTypes.func
} }
static defaultProps = { static defaultProps = {
response: fromJS({}), response: fromJS({}),
onContentTypeChange: () => {}
}; };
_onContentTypeChange = (value) => {
const { onContentTypeChange, controlsAcceptHeader } = this.props
this.setState({ responseContentType: value })
onContentTypeChange({
value: value,
controlsAcceptHeader
})
}
render() { render() {
let { let {
code, code,
response, response,
className, className,
fn, fn,
getComponent, getComponent,
specSelectors, specSelectors,
contentType contentType,
controlsAcceptHeader
} = this.props } = this.props
let { inferSchema } = fn let { inferSchema } = fn
@@ -94,6 +107,14 @@ export default class Response extends React.Component {
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0 includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
}) : null }) : null
} }
if(examples) {
examples = examples.map(example => {
// Remove unwanted properties from examples
return example.set("$$ref", undefined)
})
}
let example = getExampleComponent( sampleResponse, examples, HighlightCode ) let example = getExampleComponent( sampleResponse, examples, HighlightCode )
return ( return (
@@ -107,17 +128,24 @@ export default class Response extends React.Component {
<Markdown source={ response.get( "description" ) } /> <Markdown source={ response.get( "description" ) } />
</div> </div>
{ isOAS3 ? <ContentType { isOAS3 ?
value={this.state.responseContentType} <div className={cx("response-content-type", {
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() } "controls-accept-header": controlsAcceptHeader
onChange={(val) => this.setState({ responseContentType: val })} })}>
className="response-content-type" /> : null } <ContentType
value={this.state.responseContentType}
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() }
onChange={this._onContentTypeChange}
/>
{ controlsAcceptHeader ? <small>Controls <code>Accept</code> header.</small> : null }
</div>
: null }
{ example ? ( { example ? (
<ModelExample <ModelExample
getComponent={ getComponent } getComponent={ getComponent }
specSelectors={ specSelectors } specSelectors={ specSelectors }
schema={ fromJS(schema) } schema={ fromJSOrdered(schema) }
example={ example }/> example={ example }/>
) : null} ) : null}
+30 -3
View File
@@ -1,7 +1,7 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { fromJS } from "immutable" import { fromJS } from "immutable"
import { defaultStatusCode } from "core/utils" import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
export default class Responses extends React.Component { export default class Responses extends React.Component {
@@ -14,6 +14,7 @@ export default class Responses extends React.Component {
getComponent: PropTypes.func.isRequired, getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired, specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired, specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired, pathMethod: PropTypes.array.isRequired,
displayRequestDuration: PropTypes.bool.isRequired, displayRequestDuration: PropTypes.bool.isRequired,
fn: PropTypes.object.isRequired, fn: PropTypes.object.isRequired,
@@ -29,8 +30,28 @@ export default class Responses extends React.Component {
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val) onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
onResponseContentTypeChange = ({ controlsAcceptHeader, value }) => {
const { oas3Actions, pathMethod } = this.props
if(controlsAcceptHeader) {
oas3Actions.setResponseContentType({
value,
pathMethod
})
}
}
render() { render() {
let { responses, request, tryItOutResponse, getComponent, getConfigs, specSelectors, fn, producesValue, displayRequestDuration } = this.props let {
responses,
request,
tryItOutResponse,
getComponent,
getConfigs,
specSelectors,
fn,
producesValue,
displayRequestDuration
} = this.props
let defaultCode = defaultStatusCode( responses ) let defaultCode = defaultStatusCode( responses )
const ContentType = getComponent( "contentType" ) const ContentType = getComponent( "contentType" )
@@ -39,6 +60,11 @@ export default class Responses extends React.Component {
let produces = this.props.produces && this.props.produces.size ? this.props.produces : Responses.defaultProps.produces let produces = this.props.produces && this.props.produces.size ? this.props.produces : Responses.defaultProps.produces
const isSpecOAS3 = specSelectors.isOAS3()
const acceptControllingResponse = isSpecOAS3 ?
getAcceptControllingResponse(responses) : null
return ( return (
<div className="responses-wrapper"> <div className="responses-wrapper">
<div className="opblock-section-header"> <div className="opblock-section-header">
@@ -78,7 +104,6 @@ export default class Responses extends React.Component {
<tbody> <tbody>
{ {
responses.entrySeq().map( ([code, response]) => { responses.entrySeq().map( ([code, response]) => {
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : "" let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
return ( return (
<Response key={ code } <Response key={ code }
@@ -88,6 +113,8 @@ export default class Responses extends React.Component {
code={ code } code={ code }
response={ response } response={ response }
specSelectors={ specSelectors } specSelectors={ specSelectors }
controlsAcceptHeader={response === acceptControllingResponse}
onContentTypeChange={this.onResponseContentTypeChange}
contentType={ producesValue } contentType={ producesValue }
getComponent={ getComponent }/> getComponent={ getComponent }/>
) )
+2 -1
View File
@@ -64,7 +64,8 @@ export default function authorize ( { auth, authActions, errActions, configs, au
} }
} }
let url = [schema.get("authorizationUrl"), query.join("&")].join("?") let authorizationUrl = schema.get("authorizationUrl")
let url = [authorizationUrl, query.join("&")].join(authorizationUrl.indexOf("?") === -1 ? "?" : "&")
// pass action authorizeOauth2 and authentication data through window // pass action authorizeOauth2 and authentication data through window
// to authorize with oauth2 // to authorize with oauth2
@@ -1,4 +1,5 @@
import { setHash } from "./helpers" import { setHash } from "./helpers"
import { createDeepLinkPath } from "core/utils"
export const show = (ori, { getConfigs }) => (...args) => { export const show = (ori, { getConfigs }) => (...args) => {
ori(...args) ori(...args)
@@ -19,12 +20,12 @@ export const show = (ori, { getConfigs }) => (...args) => {
if(type === "operations") { if(type === "operations") {
let [, tag, operationId] = thing let [, tag, operationId] = thing
setHash(`/${tag}/${operationId}`) setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`)
} }
if(type === "operations-tag") { if(type === "operations-tag") {
let [, tag] = thing let [, tag] = thing
setHash(`/${tag}`) setHash(`/${createDeepLinkPath(tag)}`)
} }
} }
@@ -1,4 +1,5 @@
import scrollTo from "scroll-to-element" import scrollTo from "scroll-to-element"
import { escapeDeepLinkPath } from "core/utils"
const SCROLL_OFFSET = -5 const SCROLL_OFFSET = -5
let hasHashBeenParsed = false let hasHashBeenParsed = false
@@ -34,14 +35,14 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations-tag", tag], true)
layoutActions.show(["operations", tag, operationId], true) layoutActions.show(["operations", tag, operationId], true)
scrollTo(`#operations-${tag}-${operationId}`, { scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, {
offset: SCROLL_OFFSET offset: SCROLL_OFFSET
}) })
} else if(tag) { } else if(tag) {
// Pre-expand and scroll to the tag // Pre-expand and scroll to the tag
layoutActions.show(["operations-tag", tag], true) layoutActions.show(["operations-tag", tag], true)
scrollTo(`#operations-tag-${tag}`, { scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, {
offset: SCROLL_OFFSET offset: SCROLL_OFFSET
}) })
} }
+8
View File
@@ -4,6 +4,7 @@
export const UPDATE_SELECTED_SERVER = "oas3_set_servers" export const UPDATE_SELECTED_SERVER = "oas3_set_servers"
export const UPDATE_REQUEST_BODY_VALUE = "oas3_set_request_body_value" export const UPDATE_REQUEST_BODY_VALUE = "oas3_set_request_body_value"
export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type" export const UPDATE_REQUEST_CONTENT_TYPE = "oas3_set_request_content_type"
export const UPDATE_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type"
export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value" export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value"
export function setSelectedServer (selectedServerUrl) { export function setSelectedServer (selectedServerUrl) {
@@ -27,6 +28,13 @@ export function setRequestContentType ({ value, pathMethod }) {
} }
} }
export function setResponseContentType ({ value, pathMethod }) {
return {
type: UPDATE_RESPONSE_CONTENT_TYPE,
payload: { value, pathMethod }
}
}
export function setServerVariableValue ({ server, key, val }) { export function setServerVariableValue ({ server, key, val }) {
return { return {
type: UPDATE_SERVER_VARIABLE_VALUE, type: UPDATE_SERVER_VARIABLE_VALUE,
+6 -1
View File
@@ -2,7 +2,8 @@ import {
UPDATE_SELECTED_SERVER, UPDATE_SELECTED_SERVER,
UPDATE_REQUEST_BODY_VALUE, UPDATE_REQUEST_BODY_VALUE,
UPDATE_REQUEST_CONTENT_TYPE, UPDATE_REQUEST_CONTENT_TYPE,
UPDATE_SERVER_VARIABLE_VALUE UPDATE_SERVER_VARIABLE_VALUE,
UPDATE_RESPONSE_CONTENT_TYPE
} from "./actions" } from "./actions"
export default { export default {
@@ -17,6 +18,10 @@ export default {
let [path, method] = pathMethod let [path, method] = pathMethod
return state.setIn( [ "requestData", path, method, "requestContentType" ], value) return state.setIn( [ "requestData", path, method, "requestContentType" ], value)
}, },
[UPDATE_RESPONSE_CONTENT_TYPE]: (state, { payload: { value, pathMethod } } ) =>{
let [path, method] = pathMethod
return state.setIn( [ "requestData", path, method, "responseContentType" ], value)
},
[UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{ [UPDATE_SERVER_VARIABLE_VALUE]: (state, { payload: { server, key, val } } ) =>{
return state.setIn( [ "serverVariableValues", server, key ], val) return state.setIn( [ "serverVariableValues", server, key ], val)
}, },
+5
View File
@@ -30,6 +30,11 @@ export const requestContentType = onlyOAS3((state, path, method) => {
} }
) )
export const responseContentType = onlyOAS3((state, path, method) => {
return state.getIn(["requestData", path, method, "responseContentType"]) || null
}
)
export const serverVariableValue = onlyOAS3((state, server, key) => { export const serverVariableValue = onlyOAS3((state, server, key) => {
return state.getIn(["serverVariableValues", server, key]) || null return state.getIn(["serverVariableValues", server, key]) || null
} }
@@ -49,7 +49,7 @@ class Parameters extends Component {
onChangeKey, onChangeKey,
} = this.props } = this.props
changeParam( onChangeKey, param.get("name"), value, isXml) changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
} }
onChangeConsumesWrapper = ( val ) => { onChangeConsumesWrapper = ( val ) => {
+3 -3
View File
@@ -130,10 +130,10 @@ export const formatIntoYaml = () => ({specActions, specSelectors}) => {
} }
} }
export function changeParam( path, paramName, value, isXml ){ export function changeParam( path, paramName, paramIn, value, isXml ){
return { return {
type: UPDATE_PARAM, type: UPDATE_PARAM,
payload:{ path, value, paramName, isXml } payload:{ path, value, paramName, paramIn, isXml }
} }
} }
@@ -206,7 +206,6 @@ export const executeRequest = (req) =>
// if url is relative, parseUrl makes it absolute by inferring from `window.location` // if url is relative, parseUrl makes it absolute by inferring from `window.location`
req.contextUrl = parseUrl(specSelectors.url()).toString() req.contextUrl = parseUrl(specSelectors.url()).toString()
if(op && op.operationId) { if(op && op.operationId) {
req.operationId = op.operationId req.operationId = op.operationId
} else if(op && pathName && method) { } else if(op && pathName && method) {
@@ -218,6 +217,7 @@ export const executeRequest = (req) =>
req.server = oas3Selectors.selectedServer() req.server = oas3Selectors.selectedServer()
req.serverVariables = oas3Selectors.serverVariables(req.server).toJS() req.serverVariables = oas3Selectors.serverVariables(req.server).toJS()
req.requestContentType = oas3Selectors.requestContentType(pathName, method) req.requestContentType = oas3Selectors.requestContentType(pathName, method)
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
const requestBody = oas3Selectors.requestBodyValue(pathName, method) const requestBody = oas3Selectors.requestBodyValue(pathName, method)
if(isJSONObject(requestBody)) { if(isJSONObject(requestBody)) {
+3 -2
View File
@@ -40,9 +40,10 @@ export default {
}, },
[UPDATE_PARAM]: ( state, {payload} ) => { [UPDATE_PARAM]: ( state, {payload} ) => {
let { path, paramName, value, isXml } = payload let { path, paramName, paramIn, value, isXml } = payload
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => { return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
const index = parameters.findIndex(p => p.get( "name" ) === paramName ) const index = parameters.findIndex(p => p.get( "name" ) === paramName && p.get("in") === paramIn )
if (!(value instanceof win.File)) { if (!(value instanceof win.File)) {
value = fromJSOrdered( value ) value = fromJSOrdered( value )
} }
+3 -3
View File
@@ -260,10 +260,10 @@ export const allowTryItOutFor = () => {
} }
// Get the parameter value by parameter name // Get the parameter value by parameter name
export function getParameter(state, pathMethod, name) { export function getParameter(state, pathMethod, name, inType) {
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([])) let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
return params.filter( (p) => { return params.filter( (p) => {
return Map.isMap(p) && p.get("name") === name return Map.isMap(p) && p.get("name") === name && p.get("in") === inType
}).first() }).first()
} }
@@ -280,7 +280,7 @@ export function parameterValues(state, pathMethod, isXml) {
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([])) let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
return params.reduce( (hash, p) => { return params.reduce( (hash, p) => {
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value") let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
return hash.set(p.get("name"), value) return hash.set(`${p.get("in")}.${p.get("name")}`, value)
}, fromJS({})) }, fromJS({}))
} }
+48 -1
View File
@@ -8,6 +8,7 @@ import some from "lodash/some"
import eq from "lodash/eq" import eq from "lodash/eq"
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn" import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
import win from "./window" import win from "./window"
import cssEscape from "css.escape"
const DEFAULT_REPONSE_KEY = "default" const DEFAULT_REPONSE_KEY = "default"
@@ -499,12 +500,25 @@ export const validateString = ( val ) => {
} }
} }
export const validateDateTime = (val) => {
if (isNaN(Date.parse(val))) {
return "Value must be a DateTime"
}
}
export const validateGuid = (val) => {
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
return "Value must be a Guid"
}
}
// validation of parameters before execute // validation of parameters before execute
export const validateParam = (param, isXml) => { export const validateParam = (param, isXml) => {
let errors = [] let errors = []
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value") let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
let required = param.get("required") let required = param.get("required")
let type = param.get("type") let type = param.get("type")
let format = param.get("format")
/* /*
If the parameter is required OR the parameter has a value (meaning optional, but filled in) If the parameter is required OR the parameter has a value (meaning optional, but filled in)
@@ -527,7 +541,14 @@ export const validateParam = (param, isXml) => {
} }
if ( type === "string" ) { if ( type === "string" ) {
let err = validateString(value) let err
if (format === "date-time") {
err = validateDateTime(value)
} else if (format === "uuid") {
err = validateGuid(value)
} else {
err = validateString(value)
}
if (!err) return errors if (!err) return errors
errors.push(err) errors.push(err)
} else if ( type === "boolean" ) { } else if ( type === "boolean" ) {
@@ -650,3 +671,29 @@ export const shallowEqualKeys = (a,b, keys) => {
return eq(a[key], b[key]) return eq(a[key], b[key])
}) })
} }
export function getAcceptControllingResponse(responses) {
if(!Im.OrderedMap.isOrderedMap(responses)) {
// wrong type!
return null
}
if(!responses.size) {
// responses is empty
return null
}
const suitable2xxResponse = responses.find((res, k) => {
return k.startsWith("2") && Object.keys(res.get("content") || {}).length > 0
})
// try to find a suitable `default` responses
const defaultResponse = responses.get("default") || Im.OrderedMap()
const defaultResponseMediaTypes = (defaultResponse.get("content") || Im.OrderedMap()).keySeq().toJS()
const suitableDefaultResponse = defaultResponseMediaTypes.length ? defaultResponse : null
return suitable2xxResponse || suitableDefaultResponse
}
export const createDeepLinkPath = (str) => typeof str == "string" || str instanceof String ? str.trim().replace(/\s/g, "_") : ""
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )
+11
View File
@@ -775,6 +775,17 @@
.response-content-type { .response-content-type {
padding-top: 1em; padding-top: 1em;
&.controls-accept-header {
select {
border-color: green;
}
small {
color: green;
font-size: .7em;
}
}
} }
@keyframes blinker @keyframes blinker
+2 -1
View File
@@ -237,7 +237,8 @@ span
.prop-name .prop-name
{ {
display: inline-block; display: inline-block;
width: 100px; margin-right: 1em;
width: 8em;
} }
.prop-type .prop-type
+49
View File
@@ -0,0 +1,49 @@
/* eslint-env mocha */
import React from "react"
import expect from "expect"
import { shallow } from "enzyme"
import { fromJS } from "immutable"
import PrimitiveModel from "components/primitive-model"
describe("<PrimitiveModel/>", function() {
describe("Model name", function() {
const dummyComponent = () => null
const components = {
Markdown: dummyComponent,
EnumModel: dummyComponent
}
const props = {
getComponent: c => components[c],
name: "Name from props",
depth: 1,
schema: fromJS({
type: "string",
title: "Custom model title"
})
}
it("renders the schema's title", function() {
// When
const wrapper = shallow(<PrimitiveModel {...props}/>)
const modelTitleEl = wrapper.find("span.model-title")
expect(modelTitleEl.length).toEqual(1)
// Then
expect( modelTitleEl.text() ).toEqual( "Custom model title" )
})
it("falls back to the passed-in `name` prop for the title", function() {
// When
props.schema = fromJS({
type: "string"
})
const wrapper = shallow(<PrimitiveModel {...props}/>)
const modelTitleEl = wrapper.find("span.model-title")
expect(modelTitleEl.length).toEqual(1)
// Then
expect( modelTitleEl.text() ).toEqual( "Name from props" )
})
})
} )
+58
View File
@@ -0,0 +1,58 @@
import React from "react"
import expect from "expect"
import { shallow } from "enzyme"
import { fromJS } from "immutable"
import Response from "components/response"
import ModelExample from "components/model-example"
import { inferSchema } from "corePlugins/samples/fn"
describe("<Response />", function() {
const dummyComponent = () => null
const components = {
headers: dummyComponent,
highlightCode: dummyComponent,
modelExample: ModelExample,
Markdown: dummyComponent,
operationLink: dummyComponent,
contentType: dummyComponent
}
const props = {
getComponent: c => components[c],
specSelectors: {
isOAS3() {
return false
}
},
fn: {
inferSchema
},
contentType: "application/json",
className: "for-test",
response: fromJS({
type: "object",
properties: {
// Note reverse order: c, b, a
"c": {
type: "integer"
},
"b": {
type: "boolean"
},
"a": {
type: "string"
}
}
}),
code: "200"
}
it("renders the model-example schema properties in order", function() {
const wrapper = shallow(<Response {...props}/>)
const renderedModelExample = wrapper.find(ModelExample)
expect(renderedModelExample.length).toEqual(1)
// Assert the schema's properties have maintained their order
const modelExampleSchemaProperties = renderedModelExample.props().schema.toJS().properties
expect( Object.keys(modelExampleSchemaProperties) ).toEqual(["c", "b", "a"])
})
})
+39
View File
@@ -0,0 +1,39 @@
/* eslint-env mocha */
import expect, { createSpy } from "expect"
import { fromJS } from "immutable"
import win from "core/window"
import oauth2Authorize from "core/oauth2-authorize"
describe("oauth2", function () {
let mockSchema = {
flow: "accessCode",
authorizationUrl: "https://testAuthorizationUrl"
}
let authConfig = {
auth: { schema: { get: (key)=> mockSchema[key] } },
authActions: {},
errActions: {},
configs: { oauth2RedirectUrl: "" },
authConfigs: {}
}
describe("authorize redirect", function () {
it("should build authorize url", function() {
win.open = createSpy()
oauth2Authorize(authConfig)
expect(win.open.calls.length).toEqual(1)
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?response_type=code&redirect_uri=&state=")
})
it("should append query paramters to authorizeUrl with query parameters", function() {
win.open = createSpy()
mockSchema.authorizationUrl = "https://testAuthorizationUrl?param=1"
oauth2Authorize(authConfig)
expect(win.open.calls.length).toEqual(1)
expect(win.open.calls[0].arguments[0]).toMatch("https://testAuthorizationUrl?param=1&response_type=code&redirect_uri=&state=")
})
})
})
+4 -4
View File
@@ -29,8 +29,8 @@ describe("spec plugin - selectors", function(){
"/one": { "/one": {
get: { get: {
parameters: [ parameters: [
{ name: "one", value: 1}, { name: "one", in: "query", value: 1},
{ name: "two", value: "duos"} { name: "two", in: "query", value: "duos"}
] ]
} }
} }
@@ -43,8 +43,8 @@ describe("spec plugin - selectors", function(){
// Then // Then
expect(paramValues.toJS()).toEqual({ expect(paramValues.toJS()).toEqual({
one: 1, "query.one": 1,
two: "duos" "query.two": "duos"
}) })
}) })
+177 -3
View File
@@ -1,7 +1,7 @@
/* eslint-env mocha */ /* eslint-env mocha */
import expect from "expect" import expect from "expect"
import { fromJS } from "immutable" import { fromJS, OrderedMap } from "immutable"
import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils" import { mapToList, validateDateTime, validateGuid, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered, getAcceptControllingResponse, createDeepLinkPath, escapeDeepLinkPath } from "core/utils"
import win from "core/window" import win from "core/window"
describe("utils", function() { describe("utils", function() {
@@ -158,7 +158,7 @@ describe("utils", function() {
}) })
}) })
describe("validateFile", function() { describe("validateFile", function() {
let errorMessage = "Value must be a file" let errorMessage = "Value must be a file"
it("validates against objects which are instances of 'File'", function() { it("validates against objects which are instances of 'File'", function() {
@@ -171,6 +171,33 @@ describe("utils", function() {
}) })
}) })
describe("validateDateTime", function() {
let errorMessage = "Value must be a DateTime"
it("doesn't return for valid dates", function() {
expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy()
})
it("returns a message for invalid input'", function() {
expect(validateDateTime(null)).toEqual(errorMessage)
expect(validateDateTime("string")).toEqual(errorMessage)
})
})
describe("validateGuid", function() {
let errorMessage = "Value must be a Guid"
it("doesn't return for valid guid", function() {
expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
})
it("returns a message for invalid input'", function() {
expect(validateGuid(1)).toEqual(errorMessage)
expect(validateGuid("string")).toEqual(errorMessage)
})
})
describe("validateParam", function() { describe("validateParam", function() {
let param = null let param = null
let result = null let result = null
@@ -581,5 +608,152 @@ describe("utils", function() {
const result = fromJSOrdered(param).toJS() const result = fromJSOrdered(param).toJS()
expect( result ).toEqual( [1, 1, 2, 3, 5, 8] ) expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
}) })
})
describe("getAcceptControllingResponse", () => {
it("should return the first 2xx response with a media type", () => {
const responses = fromJSOrdered({
"200": {
content: {
"application/json": {
schema: {
type: "object"
}
}
}
},
"201": {
content: {
"application/json": {
schema: {
type: "object"
}
}
}
}
})
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("200"))
}) })
it("should skip 2xx responses without defined media types", () => {
const responses = fromJSOrdered({
"200": {
content: {
"application/json": {
schema: {
type: "object"
}
}
}
},
"201": {
content: {
"application/json": {
schema: {
type: "object"
}
}
}
}
})
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("201"))
})
it("should default to the `default` response if it has defined media types", () => {
const responses = fromJSOrdered({
"200": {
description: "quite empty"
},
"201": {
description: "quite empty"
},
default: {
content: {
"application/json": {
schema: {
type: "object"
}
}
}
}
})
expect(getAcceptControllingResponse(responses)).toEqual(responses.get("default"))
})
it("should return null if there are no suitable controlling responses", () => {
const responses = fromJSOrdered({
"200": {
description: "quite empty"
},
"201": {
description: "quite empty"
},
"default": {
description: "also empty.."
}
})
expect(getAcceptControllingResponse(responses)).toBe(null)
})
it("should return null if an empty OrderedMap is passed", () => {
const responses = fromJSOrdered()
expect(getAcceptControllingResponse(responses)).toBe(null)
})
it("should return null if anything except an OrderedMap is passed", () => {
const responses = {}
expect(getAcceptControllingResponse(responses)).toBe(null)
})
})
describe("createDeepLinkPath", function() {
it("creates a deep link path replacing spaces with underscores", function() {
const result = createDeepLinkPath("tag id with spaces")
expect(result).toEqual("tag_id_with_spaces")
})
it("trims input when creating a deep link path", function() {
let result = createDeepLinkPath(" spaces before and after ")
expect(result).toEqual("spaces_before_and_after")
result = createDeepLinkPath(" ")
expect(result).toEqual("")
})
it("creates a deep link path with special characters", function() {
const result = createDeepLinkPath("!@#$%^&*(){}[]")
expect(result).toEqual("!@#$%^&*(){}[]")
})
it("returns an empty string for invalid input", function() {
expect( createDeepLinkPath(null) ).toEqual("")
expect( createDeepLinkPath(undefined) ).toEqual("")
expect( createDeepLinkPath(1) ).toEqual("")
expect( createDeepLinkPath([]) ).toEqual("")
expect( createDeepLinkPath({}) ).toEqual("")
})
})
describe("escapeDeepLinkPath", function() {
it("creates and escapes a deep link path", function() {
const result = escapeDeepLinkPath("tag id with spaces?")
expect(result).toEqual("tag_id_with_spaces\\?")
})
it("escapes a deep link path that starts with a number", function() {
const result = escapeDeepLinkPath("123")
expect(result).toEqual("\\31 23")
})
it("escapes a deep link path with a class selector", function() {
const result = escapeDeepLinkPath("hello.world")
expect(result).toEqual("hello\\.world")
})
it("escapes a deep link path with an id selector", function() {
const result = escapeDeepLinkPath("hello#world")
expect(result).toEqual("hello\\#world")
})
})
}) })