Compare commits

...
142 Commits
Author SHA1 Message Date
kyle fa24b6aec8 Merge pull request #3723 from swagger-api/v/3.3.1
v3.3.1
2017-10-02 15:24:39 -07:00
Kyle Shockey 2f59c4a5f4 v3.3.1 2017-10-02 15:18:33 -07:00
kyle d32fe02713 Merge pull request #3722 from swagger-api/bug/3718-oas3-requestbody-errors
Fix problems regarding request body display
2017-10-02 14:53:14 -07:00
kyle 446bda369c Merge branch 'master' into bug/3718-oas3-requestbody-errors 2017-10-02 14:47:43 -07:00
Kyle Shockey 8354132915 Fix problems regarding request body display 2017-10-02 14:45:51 -07:00
kyle ca28c8c8d6 Merge pull request #3720 from MyTeamName/doc-patch
doc add markdown Github flavored syntax highlights
2017-10-02 10:01:56 -07:00
Jeff Puckett de231c0325 doc add markdown Github flavored syntax highlights 2017-10-02 15:33:48 +00:00
kyle 1d00c952d6 Merge pull request #3717 from swagger-api/v/3.3.0
v/3.3.0
2017-09-29 18:54:05 -07:00
Kyle Shockey 4e6dc3beec Rebuild dist 2017-09-29 18:48:30 -07:00
Kyle Shockey 4ff629eddd v3.3.0 2017-09-29 18:43:21 -07:00
kyle dd02778b55 Merge pull request #3716 from swagger-api/ft/oas3-disable-auth
Disable Swagger2 auth features in OAS3
2017-09-29 17:56:15 -07:00
Kyle Shockey e15b4c85c0 ESLint.... 2017-09-29 17:51:12 -07:00
Kyle Shockey 7e6f74080f Disable Swagger2 auth features in OAS3 2017-09-29 17:49:15 -07:00
kyle c6a664302a Merge pull request #3421 from dalbani/feature/request-url
Restore "Request URL" in live response section
2017-09-29 14:51:37 -07:00
kyle ac634c61ce Merge branch 'master' into feature/request-url 2017-09-29 14:38:42 -07:00
kyle 37399958a2 Merge pull request #3531 from mhw/array-model-markdown-description
Array description should be processed as Markdown.
2017-09-29 14:15:20 -07:00
kyle 44882700c2 Merge branch 'master' into array-model-markdown-description 2017-09-29 14:06:01 -07:00
kyle cecc3b3573 Merge pull request #3628 from gilbode/ft/default_model_rendering
Add defaultModelRendering parameter.
2017-09-29 13:55:15 -07:00
kyle 263f6feb2f Merge branch 'master' into ft/default_model_rendering 2017-09-29 13:29:04 -07:00
kyle 356dc81b18 Merge pull request #3712 from owenconti/bug/swagger-editor-1502
Fixes swagger-editor/#1502.
2017-09-29 12:45:00 -07:00
Kyle Shockey a7acd9e004 Remove react-remarkable from package.json 2017-09-29 12:38:00 -07:00
kyle ef9fe9d755 Merge branch 'master' into bug/swagger-editor-1502 2017-09-29 12:16:01 -07:00
kyle ca98ed114a Merge pull request #3647 from JoshuaWhatley/bug/3474
Bug/3474
2017-09-28 18:16:40 -07:00
kyle c5534a506e Merge branch 'master' into bug/3474 2017-09-28 18:12:26 -07:00
kyle e0fb125a48 Merge pull request #3703 from heldersepu/ft/validation
Add validateMaximum & validateMinimum
2017-09-28 18:04:14 -07:00
Kyle Shockey 012313e236 Handle cases where maximum and minimum are 0 2017-09-28 17:59:07 -07:00
kyle 27da2a7d3b Merge branch 'master' into ft/validation 2017-09-28 17:53:14 -07:00
kyle 67dbad445d Merge pull request #3701 from heldersepu/master
Add validation for min and max length
2017-09-28 17:48:23 -07:00
HelderSepu a408fb1f23 Correction from @shockey 2017-09-28 20:40:22 -04:00
kyle 3a7a8c9c67 Merge branch 'master' into master 2017-09-28 15:58:41 -07:00
kyle 239d105974 Merge pull request #3708 from owenconti/bug/3706-enum-param
Fixes #3706
2017-09-27 20:21:12 -07:00
kyle 4f1a8abd0d Merge branch 'master' into bug/3706-enum-param 2017-09-27 19:48:37 -07:00
kyle 13fd88f1d2 Merge pull request #3709 from ELE3E/master
Fixes #3694: Apply conditions for generating download link correctly
2017-09-27 19:48:02 -07:00
Owen Conti 590819ad9b Fixes swagger-editor/#1502.
Change logic for markdown rendering to:

1. Convert source markdown to HTML
2. Sanitize HTML
3. Send sanitized HTML to markdown renderer
2017-09-27 18:05:12 -06:00
Elvin Lemmens ca1a0fa544 Apply conditions for generating download link correctly
Invalid application of AND/OR statements prevented file downloads of other types than application/octet-stream from generating a download link
2017-09-27 12:34:46 +02:00
Owen Conti 31e7ce0c5e Fixes #3706
Add missing "in" argument to `getParameter`
2017-09-25 21:26:44 -06:00
kyle d1258c6b8c Merge branch 'master' into ft/validation 2017-09-24 18:09:19 -07:00
HelderSepu 515726b386 Add test for negative num
Testing valid negative number with min and max
2017-09-24 15:45:42 -04:00
HelderSepu 7d40d72281 Add validateMaximum & validateMinimum
This address some of the validation requested on Issue #993
2017-09-24 11:43:47 -04:00
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
HelderSepu a5c7083726 Add validation for min and max length 2017-09-23 14:14:58 -04: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
Joshua Whatley 14f47654ee Merge branch 'master' into bug/3474 2017-09-21 16:54:54 -07: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
Joshua Whatley 6488cbb649 Merge branch 'master' into bug/3474 2017-09-18 11:27:10 -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
Joshua Whatley 82b9341a06 Changing word-break to follow standard
Changed "break-word" to "break-all" as this is standard across all
browsers and results with consistent behavior.
2017-09-13 21:23:49 -07: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
Ron b9be09709a Merge branch 'master' into feature/request-url 2017-09-11 05:05:08 -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
Joshua Whatley 63ee0a874c break path if it would otherwise overflow 2017-09-08 16:53:43 -07:00
Joshua Whatley 7a4ef07c73 Merge remote-tracking branch 'refs/remotes/swagger-api/master' 2017-09-08 12:55:49 -07:00
Owen Conti 3b9940567b Fix property names being displayed in array models 2017-09-07 18:28:38 -06:00
Mike Gilbode d7ae284a0c Add defaultModelRendering parameter. 2017-08-30 23:30:57 -04:00
Kyle Shockey a6944a279c Remove getComponent call for RequestUrl 2017-08-21 17:21:48 -07:00
Kyle Shockey b2f7953319 Merge branch 'master' of github.com:swagger-api/swagger-ui into dalbani-feature/request-url 2017-08-21 17:19:33 -07:00
Kyle Shockey 39450f7364 Merge branch 'feature/request-url' of https://github.com/dalbani/swagger-ui into dalbani-feature/request-url 2017-08-21 17:19:17 -07:00
Matthew Seal 54b383a7d2 Updated docs for correct usage of SWAGGER_JSON 2017-08-15 18:02:17 -07:00
Kyle 04fb27b46d Merge branch 'master' into array-model-markdown-description 2017-08-11 17:42:30 -07:00
Kyle fd44416238 Merge branch 'master' into array-model-markdown-description 2017-08-10 13:58:38 -07:00
Mark H. Wilkinson d7424ff248 Array description should be processed as Markdown. 2017-08-07 12:33:15 +01: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
Damiano Albani 175bc486c7 Merge branch 'master' into feature/request-url 2017-07-21 23:41:21 +02:00
Damiano Albani cd6b86e710 Restore "Request URL" in live response section 2017-07-20 14:12:34 +02:00
50 changed files with 1095 additions and 161 deletions
+9 -7
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.
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-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](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) 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).
@@ -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
------------------ | ------------ | -------------------------- | -----
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.3.1 | 2017-10-02 | 2.0, 3.0 | [tag v3.3.1](https://github.com/swagger-api/swagger-ui/tree/v3.3.1)
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.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
```
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
@@ -119,7 +119,7 @@ scopeSeparator | scope separator for passing scopes, encoded before calling, def
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`
```
```javascript
const ui = SwaggerUIBundle({...})
// Method can be called in any place after calling constructor SwaggerUIBundle
@@ -151,6 +151,8 @@ domNode | The HTML DOM element inside which SwaggerUi will put the user interfac
oauth2RedirectUrl | OAuth redirect URL
tagsSorter | Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be set to 'model' or 'example', and the default is 'example'.
defaultModelExpandDepth | The default expansion depth for models. The default value is 1.
configUrl | Configs URL
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
@@ -169,7 +171,7 @@ showMutatedRequest | If set to `true` (the default), uses the mutated request re
#### Topbar plugin
Topbar plugin enables top bar with input for spec path and explore button or a dropdown if `urls` is used. By default the plugin is enabled, and to disable it you need to remove Topbar plugin from presets in `src/standalone/index.js`:
```
```javascript
let preset = [
// TopbarPlugin,
ConfigsPlugin,
+17 -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;;;;;AAonMA;;;;;;AAm5DA;;;;;;;;;;;;;;;;;;;;;;;;;;AAukUA;;;;;;;;;;;;;;AAq4JA;AA4+iBA;;;;;;;;;AA8oIA;;;;;AA87QA;;;;;AAynBA;AAo0CA;;;;;;AA6gZA;;;;;;AAkzZA;AAixYA","sourceRoot":""}
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA80CA;;;;;;AAqpFA","sourceRoot":""}
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA6mCA;;;;;;AA41FA","sourceRoot":""}
+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;;;;;;AA67eA","sourceRoot":""}
+6 -3
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.2.0",
"version": "3.3.1",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -41,6 +41,9 @@
"dependencies": {
"base64-js": "^1.2.0",
"brace": "0.7.0",
"classnames": "^2.2.5",
"commonmark": "^0.28.1",
"css.escape": "1.5.1",
"deep-extend": "0.4.1",
"expect": "1.20.2",
"getbase": "^2.8.2",
@@ -65,17 +68,17 @@
"react-motion": "0.4.4",
"react-object-inspector": "0.2.1",
"react-redux": "^4.x.x",
"react-remarkable": "1.1.1",
"react-split-pane": "0.1.57",
"redux": "^3.x.x",
"redux-immutable": "3.0.8",
"redux-logger": "*",
"remarkable": "^1.7.1",
"reselect": "2.5.3",
"sanitize-html": "^1.14.1",
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "3.1.0",
"swagger-client": "^3.2.0",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
+18 -9
View File
@@ -16,10 +16,12 @@ export default class ArrayModel extends Component {
render(){
let { getComponent, schema, depth, expandDepth, name } = this.props
let description = schema.get("description")
let items = schema.get("items")
let title = schema.get("title") || name
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
let properties = schema.filter( ( v, key) => ["type", "items", "description", "$$ref"].indexOf(key) === -1 )
const Markdown = getComponent("Markdown")
const ModelCollapse = getComponent("ModelCollapse")
const Model = getComponent("Model")
@@ -28,18 +30,25 @@ export default class ArrayModel extends Component {
<span className="model-title__text">{ title }</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">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
[
<span><Model { ...this.props } schema={ items } required={ false } depth={ depth + 1 } /></span>
{
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
<br />{ key }: { String(v) }</span>)
: null
}
{
!description ? null :
<Markdown source={ description } />
}
<span><Model { ...this.props } name={null} schema={ items } required={ false } depth={ depth + 1 } /></span>
]
{
properties.size ? <span>
{ properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={propStyle}>
<br />{ `${key}:`}{ String(v) }</span>)
}<br /></span>
: null
}
</ModelCollapse>
</span>
}
+7
View File
@@ -61,6 +61,13 @@ export default class LiveResponse extends React.Component {
return (
<div>
{ curlRequest && <Curl request={ curlRequest }/> }
{ url && <div>
<h4>Request URL</h4>
<div className="request-url">
<pre>{url}</pre>
</div>
</div>
}
<h4>Server response</h4>
<table className="responses-table">
<thead>
+11 -5
View File
@@ -7,14 +7,19 @@ export default class ModelExample extends React.Component {
specSelectors: PropTypes.object.isRequired,
schema: PropTypes.object.isRequired,
example: PropTypes.any.isRequired,
isExecute: PropTypes.bool
isExecute: PropTypes.bool,
getConfigs: PropTypes.func.isRequired
}
constructor(props, context) {
super(props, context)
let { getConfigs } = this.props
let { defaultModelRendering } = getConfigs()
if (defaultModelRendering !== "example" && defaultModelRendering !== "model") {
defaultModelRendering = "example"
}
this.state = {
activeTab: "example"
activeTab: defaultModelRendering
}
}
@@ -27,7 +32,8 @@ export default class ModelExample extends React.Component {
}
render() {
let { getComponent, specSelectors, schema, example, isExecute } = this.props
let { getComponent, specSelectors, schema, example, isExecute, getConfigs } = this.props
let { defaultModelExpandDepth } = getConfigs()
const ModelWrapper = getComponent("ModelWrapper")
return <div>
@@ -47,7 +53,7 @@ export default class ModelExample extends React.Component {
!isExecute && this.state.activeTab === "model" && <ModelWrapper schema={ schema }
getComponent={ getComponent }
specSelectors={ specSelectors }
expandDepth={ 1 } />
expandDepth={ defaultModelExpandDepth } />
}
+26 -26
View File
@@ -30,39 +30,38 @@ export default class Model extends Component {
render () {
let { getComponent, specSelectors, schema, required, name, isRef } = this.props
let ObjectModel = getComponent("ObjectModel")
let ArrayModel = getComponent("ArrayModel")
let PrimitiveModel = getComponent("PrimitiveModel")
const ObjectModel = getComponent("ObjectModel")
const ArrayModel = getComponent("ArrayModel")
const PrimitiveModel = getComponent("PrimitiveModel")
let type = "object"
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")
if ( schema && (schema.get("type") || schema.get("properties")) ) {
modelSchema = schema
} else if ( $$ref ) {
modelSchema = this.getRefSchema( modelName )
}
type = modelSchema && modelSchema.get("type")
if ( !type && modelSchema && modelSchema.get("properties") ) {
type = "object"
}
isRef = isRef !== undefined ? isRef : !!$$ref
type = schema && schema.get("type") || type
switch(type) {
case "object":
return <ObjectModel
className="object" { ...this.props }
schema={ modelSchema }
name={ modelName || name }
schema={ schema }
name={ name }
deprecated={deprecated}
isRef={ isRef!== undefined ? isRef : !!$$ref } />
isRef={ isRef } />
case "array":
return <ArrayModel
className="array" { ...this.props }
schema={ modelSchema }
name={ modelName || name }
schema={ schema }
name={ name }
deprecated={deprecated}
required={ required } />
case "string":
@@ -73,9 +72,10 @@ export default class Model extends Component {
return <PrimitiveModel
{ ...this.props }
getComponent={ getComponent }
schema={ modelSchema }
name={ modelName || name }
schema={ schema }
name={ name }
deprecated={deprecated}
required={ required }/> }
required={ required }/>
}
}
}
+2 -2
View File
@@ -13,7 +13,7 @@ export default class Models extends Component {
render(){
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
let definitions = specSelectors.definitions()
let { docExpansion } = getConfigs()
let { docExpansion, defaultModelExpandDepth } = getConfigs()
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
const ModelWrapper = getComponent("ModelWrapper")
@@ -33,8 +33,8 @@ export default class Models extends Component {
definitions.entrySeq().map( ( [ name, model ])=>{
return <div className="model-container" key={ `models-section-${name}` }>
<ModelWrapper name={ name }
expandDepth={ defaultModelExpandDepth }
schema={ model }
isRef={ true }
getComponent={ getComponent }
specSelectors={ specSelectors }/>
</div>
+6 -2
View File
@@ -28,6 +28,7 @@ export default class Operation extends PureComponent {
authSelectors: PropTypes.object,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired,
@@ -117,7 +118,8 @@ export default class Operation extends PureComponent {
specSelectors,
authActions,
authSelectors,
getConfigs
getConfigs,
oas3Actions
} = this.props
let summary = operation.get("summary")
@@ -147,7 +149,7 @@ export default class Operation extends PureComponent {
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
// Merge in Live Response
if(response && response.size > 0) {
if(responses && response && response.size > 0) {
let notDocumented = !responses.get(String(response.get("status")))
response = response.set("notDocumented", notDocumented)
}
@@ -222,6 +224,7 @@ export default class Operation extends PureComponent {
specActions={ specActions }
specSelectors={ specSelectors }
pathMethod={ [path, method] }
getConfigs={ getConfigs }
/>
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <div className="opblock-schemes">
@@ -265,6 +268,7 @@ export default class Operation extends PureComponent {
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
oas3Actions={oas3Actions}
specActions={ specActions }
produces={ produces }
producesValue={ operation.get("produces_value") }
+9 -4
View File
@@ -1,7 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import { helpers } from "swagger-client"
import { createDeepLinkPath } from "core/utils"
const { opId } = helpers
export default class Operations extends React.Component {
@@ -9,6 +9,7 @@ export default class Operations extends React.Component {
static propTypes = {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
@@ -21,6 +22,7 @@ export default class Operations extends React.Component {
let {
specSelectors,
specActions,
oas3Actions,
getComponent,
layoutSelectors,
layoutActions,
@@ -34,6 +36,7 @@ export default class Operations extends React.Component {
const Operation = getComponent("operation")
const Collapse = getComponent("Collapse")
const Markdown = getComponent("Markdown")
let showSummary = layoutSelectors.showSummary()
let {
@@ -69,7 +72,7 @@ export default class Operations extends React.Component {
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
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")
return (
@@ -87,7 +90,7 @@ export default class Operations extends React.Component {
</a>
{ !tagDescription ? null :
<small>
{ tagDescription }
<Markdown source={tagDescription} />
</small>
}
@@ -124,7 +127,7 @@ export default class Operations extends React.Component {
const operationId =
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 response = specSelectors.responseFor(op.get("path"), op.get("method"))
@@ -147,6 +150,8 @@ export default class Operations extends React.Component {
specActions={ specActions }
specSelectors={ specSelectors }
oas3Actions={oas3Actions}
layoutActions={ layoutActions }
layoutSelectors={ layoutSelectors }
+2 -2
View File
@@ -47,7 +47,7 @@ export default class ParamBody extends PureComponent {
updateValues = (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 isJson = /json/i.test(consumesValue)
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 ContentType = getComponent("contentType")
// 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 consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
+8 -7
View File
@@ -11,7 +11,8 @@ export default class ParameterRow extends Component {
isExecute: PropTypes.bool,
onChangeConsumes: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired
pathMethod: PropTypes.array.isRequired,
getConfigs: PropTypes.func.isRequired
}
constructor(props, context) {
@@ -19,7 +20,7 @@ export default class ParameterRow extends Component {
let { specSelectors, pathMethod, param } = props
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") : ""
if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
@@ -30,7 +31,7 @@ export default class ParameterRow extends Component {
let { specSelectors, pathMethod, param } = props
let example = param.get("example")
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 paramValue = parameter ? parameter.get("value") : undefined
let enumValue = parameter ? parameter.get("enum") : undefined
let value
@@ -56,7 +57,7 @@ export default class ParameterRow extends Component {
}
render() {
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
let {param, onChange, getComponent, getConfigs, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
let { isOAS3 } = specSelectors
@@ -81,13 +82,12 @@ export default class ParameterRow extends Component {
const Markdown = getComponent("Markdown")
let schema = param.get("schema")
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
let isFormData = inType === "formData"
let isFormDataSupported = "FormData" in win
let required = param.get("required")
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
let parameter = specSelectors.getParameter(pathMethod, param.get("name"), param.get("in"))
let value = parameter ? parameter.get("value") : ""
return (
@@ -121,6 +121,7 @@ export default class ParameterRow extends Component {
{
bodyParam && schema ? <ModelExample getComponent={ getComponent }
getConfigs={ getConfigs }
isExecute={ isExecute }
specSelectors={ specSelectors }
schema={ schema }
+6 -3
View File
@@ -19,7 +19,8 @@ export default class Parameters extends Component {
onTryoutClick: PropTypes.func,
onCancelClick: PropTypes.func,
onChangeKey: PropTypes.array,
pathMethod: PropTypes.array.isRequired
pathMethod: PropTypes.array.isRequired,
getConfigs: PropTypes.func.isRequired
}
@@ -37,7 +38,7 @@ export default class Parameters extends Component {
onChangeKey,
} = this.props
changeParam( onChangeKey, param.get("name"), value, isXml)
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
}
onChangeConsumesWrapper = ( val ) => {
@@ -60,6 +61,7 @@ export default class Parameters extends Component {
fn,
getComponent,
getConfigs,
specSelectors,
pathMethod
} = this.props
@@ -93,8 +95,9 @@ export default class Parameters extends Component {
eachMap(parameters, (parameter) => (
<ParameterRow fn={ fn }
getComponent={ getComponent }
getConfigs={ getConfigs }
param={ parameter }
key={ parameter.get( "name" ) }
key={ `${parameter.get( "in" )}.${parameter.get("name")}` }
onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper}
specSelectors={ specSelectors }
+2 -1
View File
@@ -23,6 +23,7 @@ export default class Primitive extends Component {
let format = schema.get("format")
let xml = schema.get("xml")
let enumArray = schema.get("enum")
let title = schema.get("title") || name
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
const Markdown = getComponent("Markdown")
@@ -30,7 +31,7 @@ export default class Primitive extends Component {
return <span className="model">
<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>
{ format && <span className="prop-format">(${format})</span>}
{
+21 -18
View File
@@ -1,37 +1,40 @@
import React from "react"
import PropTypes from "prop-types"
import Remarkable from "react-remarkable"
import Remarkable from "remarkable"
import sanitize from "sanitize-html"
function Markdown({ source }) {
const sanitized = sanitizer(source)
const html = new Remarkable({
html: true,
typographer: true,
breaks: true,
linkify: true,
linkTarget: "_blank"
}).render(source)
const sanitized = sanitizer(html)
// sometimes the sanitizer returns "undefined" as a string
if(!source || !sanitized || sanitized === "undefined") {
return null
}
if ( !source || !html || !sanitized ) {
return null
}
return <div className="markdown">
<Remarkable
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
source={sanitized}
></Remarkable>
</div>
return (
<div className="markdown" dangerouslySetInnerHTML={{ __html: sanitized }}></div>
)
}
Markdown.propTypes = {
source: PropTypes.string.isRequired
source: PropTypes.string.isRequired
}
export default Markdown
const sanitizeOptions = {
textFilter: function(text) {
return text
.replace(/&quot;/g, "\"")
}
allowedTags: sanitize.defaults.allowedTags.concat([ "img" ]),
textFilter: function(text) {
return text.replace(/&quot;/g, "\"")
}
}
export function sanitizer(str) {
return sanitize(str, sanitizeOptions)
return sanitize(str, sanitizeOptions)
}
+4 -4
View File
@@ -49,10 +49,10 @@ export default class ResponseBody extends React.Component {
// Download
} else if (
/^application\/octet-stream/i.test(contentType) ||
headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"]) ||
headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"]) ||
headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"]) ||
headers["content-description"] && (/File Transfer/i).test(headers["content-description"])) {
(headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"])) ||
(headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"])) ||
(headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"])) ||
(headers["content-description"] && (/File Transfer/i).test(headers["content-description"]))) {
let contentLength = headers["content-length"] || headers["Content-Length"]
if ( !(+contentLength) ) return null
+41 -10
View File
@@ -1,7 +1,8 @@
import React from "react"
import PropTypes from "prop-types"
import cx from "classnames"
import { fromJS, Seq } from "immutable"
import { getSampleSchema } from "core/utils"
import { getSampleSchema, fromJSOrdered } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
if ( examples && examples.size ) {
@@ -44,25 +45,39 @@ export default class Response extends React.Component {
response: PropTypes.object,
className: PropTypes.string,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired,
contentType: PropTypes.string
contentType: PropTypes.string,
controlsAcceptHeader: PropTypes.bool,
onContentTypeChange: PropTypes.func
}
static defaultProps = {
response: fromJS({}),
onContentTypeChange: () => {}
};
_onContentTypeChange = (value) => {
const { onContentTypeChange, controlsAcceptHeader } = this.props
this.setState({ responseContentType: value })
onContentTypeChange({
value: value,
controlsAcceptHeader
})
}
render() {
let {
code,
response,
className,
fn,
getComponent,
getConfigs,
specSelectors,
contentType
contentType,
controlsAcceptHeader
} = this.props
let { inferSchema } = fn
@@ -94,6 +109,14 @@ export default class Response extends React.Component {
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
}) : null
}
if(examples) {
examples = examples.map(example => {
// Remove unwanted properties from examples
return example.set ? example.set("$$ref", undefined) : example
})
}
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
return (
@@ -107,17 +130,25 @@ export default class Response extends React.Component {
<Markdown source={ response.get( "description" ) } />
</div>
{ isOAS3 ? <ContentType
value={this.state.responseContentType}
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() }
onChange={(val) => this.setState({ responseContentType: val })}
className="response-content-type" /> : null }
{ isOAS3 ?
<div className={cx("response-content-type", {
"controls-accept-header": controlsAcceptHeader
})}>
<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 ? (
<ModelExample
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
schema={ fromJS(schema) }
schema={ fromJSOrdered(schema) }
example={ example }/>
) : null}
+33 -5
View File
@@ -1,7 +1,7 @@
import React from "react"
import PropTypes from "prop-types"
import { fromJS } from "immutable"
import { defaultStatusCode } from "core/utils"
import { defaultStatusCode, getAcceptControllingResponse } from "core/utils"
export default class Responses extends React.Component {
@@ -12,12 +12,13 @@ export default class Responses extends React.Component {
produces: PropTypes.object,
producesValue: PropTypes.any,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
displayRequestDuration: PropTypes.bool.isRequired,
fn: PropTypes.object.isRequired,
getConfigs: PropTypes.func.isRequired
fn: PropTypes.object.isRequired
}
static defaultProps = {
@@ -29,8 +30,28 @@ export default class Responses extends React.Component {
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() {
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 )
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
const isSpecOAS3 = specSelectors.isOAS3()
const acceptControllingResponse = isSpecOAS3 ?
getAcceptControllingResponse(responses) : null
return (
<div className="responses-wrapper">
<div className="opblock-section-header">
@@ -78,7 +104,6 @@ export default class Responses extends React.Component {
<tbody>
{
responses.entrySeq().map( ([code, response]) => {
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
return (
<Response key={ code }
@@ -88,7 +113,10 @@ export default class Responses extends React.Component {
code={ code }
response={ response }
specSelectors={ specSelectors }
controlsAcceptHeader={response === acceptControllingResponse}
onContentTypeChange={this.onResponseContentTypeChange}
contentType={ producesValue }
getConfigs={ getConfigs }
getComponent={ getComponent }/>
)
}).toArray()
+2
View File
@@ -45,6 +45,8 @@ module.exports = function SwaggerUI(opts) {
requestInterceptor: (a => a),
responseInterceptor: (a => a),
showMutatedRequest: true,
defaultModelRendering: "example",
defaultModelExpandDepth: 1,
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.
+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
// to authorize with oauth2
@@ -1,4 +1,5 @@
import { setHash } from "./helpers"
import { createDeepLinkPath } from "core/utils"
export const show = (ori, { getConfigs }) => (...args) => {
ori(...args)
@@ -19,12 +20,12 @@ export const show = (ori, { getConfigs }) => (...args) => {
if(type === "operations") {
let [, tag, operationId] = thing
setHash(`/${tag}/${operationId}`)
setHash(`/${createDeepLinkPath(tag)}/${createDeepLinkPath(operationId)}`)
}
if(type === "operations-tag") {
let [, tag] = thing
setHash(`/${tag}`)
setHash(`/${createDeepLinkPath(tag)}`)
}
}
@@ -1,4 +1,5 @@
import scrollTo from "scroll-to-element"
import { escapeDeepLinkPath } from "core/utils"
const SCROLL_OFFSET = -5
let hasHashBeenParsed = false
@@ -34,14 +35,14 @@ export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args)
layoutActions.show(["operations-tag", tag], true)
layoutActions.show(["operations", tag, operationId], true)
scrollTo(`#operations-${tag}-${operationId}`, {
scrollTo(`#operations-${escapeDeepLinkPath(tag)}-${escapeDeepLinkPath(operationId)}`, {
offset: SCROLL_OFFSET
})
} else if(tag) {
// Pre-expand and scroll to the tag
layoutActions.show(["operations-tag", tag], true)
scrollTo(`#operations-tag-${tag}`, {
scrollTo(`#operations-tag-${escapeDeepLinkPath(tag)}`, {
offset: SCROLL_OFFSET
})
}
+8
View File
@@ -4,6 +4,7 @@
export const UPDATE_SELECTED_SERVER = "oas3_set_servers"
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_RESPONSE_CONTENT_TYPE = "oas3_set_response_content_type"
export const UPDATE_SERVER_VARIABLE_VALUE = "oas3_set_server_variable_value"
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 }) {
return {
type: UPDATE_SERVER_VARIABLE_VALUE,
@@ -0,0 +1,29 @@
import { createSelector } from "reselect"
import { List } from "immutable"
import { isOAS3 as isOAS3Helper } from "../helpers"
// Helpers
function onlyOAS3(selector) {
return (ori, system) => (...args) => {
const spec = system.getSystem().specSelectors.specJson()
if(isOAS3Helper(spec)) {
return selector(...args)
} else {
return ori(...args)
}
}
}
const nullSelector = createSelector(() => null)
const OAS3NullSelector = onlyOAS3(nullSelector)
// Hasta la vista, authentication!
export const shownDefinitions = OAS3NullSelector
export const definitionsToAuthorize = OAS3NullSelector
export const getDefinitionsByNames = OAS3NullSelector
export const authorized = onlyOAS3(() => List())
export const isAuthorized = OAS3NullSelector
export const getConfigs = OAS3NullSelector
@@ -6,6 +6,7 @@ import { OrderedMap } from "immutable"
const RequestBody = ({
requestBody,
getComponent,
getConfigs,
specSelectors,
contentType,
isExecute,
@@ -27,6 +28,7 @@ const RequestBody = ({
}
<ModelExample
getComponent={ getComponent }
getConfigs={ getConfigs }
specSelectors={ specSelectors }
expandDepth={1}
isExecute={isExecute}
@@ -46,6 +48,7 @@ const RequestBody = ({
RequestBody.propTypes = {
requestBody: ImPropTypes.orderedMap.isRequired,
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
contentType: PropTypes.string.isRequired,
isExecute: PropTypes.bool.isRequired,
+4
View File
@@ -1,6 +1,7 @@
// import reducers from "./reducers"
// import * as actions from "./actions"
import * as specWrapSelectors from "./spec-extensions/wrap-selectors"
import * as authWrapSelectors from "./auth-extensions/wrap-selectors"
import * as specSelectors from "./spec-extensions/selectors"
import components from "./components"
import wrapComponents from "./wrap-components"
@@ -17,6 +18,9 @@ export default function() {
wrapSelectors: specWrapSelectors,
selectors: specSelectors
},
auth: {
wrapSelectors: authWrapSelectors
},
oas3: {
actions: oas3Actions,
reducers: oas3Reducers,
+6 -1
View File
@@ -2,7 +2,8 @@ import {
UPDATE_SELECTED_SERVER,
UPDATE_REQUEST_BODY_VALUE,
UPDATE_REQUEST_CONTENT_TYPE,
UPDATE_SERVER_VARIABLE_VALUE
UPDATE_SERVER_VARIABLE_VALUE,
UPDATE_RESPONSE_CONTENT_TYPE
} from "./actions"
export default {
@@ -17,6 +18,10 @@ export default {
let [path, method] = pathMethod
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 } } ) =>{
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) => {
return state.getIn(["serverVariableValues", server, key]) || null
}
@@ -53,6 +53,7 @@ export const basePath = OAS3NullSelector
export const consumes = OAS3NullSelector
export const produces = OAS3NullSelector
export const schemes = OAS3NullSelector
export const securityDefinitions = OAS3NullSelector
// New selectors
@@ -1,11 +1,26 @@
import React from "react"
import ReactMarkdown from "react-markdown"
import { Parser, HtmlRenderer } from "commonmark"
import { OAS3ComponentWrapFactory } from "../helpers"
import { sanitizer } from "core/components/providers/markdown"
export default OAS3ComponentWrapFactory(({ source }) => { return source ? (
<ReactMarkdown
source={sanitizer(source)}
className={"renderedMarkdown"}
/>
) : null})
export default OAS3ComponentWrapFactory(({ source }) => {
if ( source ) {
const parser = new Parser()
const writer = new HtmlRenderer()
const html = writer.render(parser.parse(source || ""))
const sanitized = sanitizer(html)
if ( !source || !html || !sanitized ) {
return null
}
return (
<ReactMarkdown
source={sanitized}
className={"renderedMarkdown"}
/>
)
}
return null
})
@@ -49,7 +49,7 @@ class Parameters extends Component {
onChangeKey,
} = this.props
changeParam( onChangeKey, param.get("name"), value, isXml)
changeParam( onChangeKey, param.get("name"), param.get("in"), value, isXml)
}
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 {
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`
req.contextUrl = parseUrl(specSelectors.url()).toString()
if(op && op.operationId) {
req.operationId = op.operationId
} else if(op && pathName && method) {
@@ -218,6 +217,7 @@ export const executeRequest = (req) =>
req.server = oas3Selectors.selectedServer()
req.serverVariables = oas3Selectors.serverVariables(req.server).toJS()
req.requestContentType = oas3Selectors.requestContentType(pathName, method)
req.responseContentType = oas3Selectors.responseContentType(pathName, method) || "*/*"
const requestBody = oas3Selectors.requestBodyValue(pathName, method)
if(isJSONObject(requestBody)) {
+3 -2
View File
@@ -40,9 +40,10 @@ export default {
},
[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 => {
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)) {
value = fromJSOrdered( value )
}
+3 -3
View File
@@ -260,10 +260,10 @@ export const allowTryItOutFor = () => {
}
// 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([]))
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()
}
@@ -280,7 +280,7 @@ export function parameterValues(state, pathMethod, isXml) {
let params = spec(state).getIn(["paths", ...pathMethod, "parameters"], fromJS([]))
return params.reduce( (hash, p) => {
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({}))
}
+96 -1
View File
@@ -8,6 +8,7 @@ import some from "lodash/some"
import eq from "lodash/eq"
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
import win from "./window"
import cssEscape from "css.escape"
const DEFAULT_REPONSE_KEY = "default"
@@ -469,6 +470,18 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|| objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
}
export const validateMaximum = ( val, max ) => {
if (val > max) {
return "Value must be less than Maximum"
}
}
export const validateMinimum = ( val, min ) => {
if (val < min) {
return "Value must be greater than Minimum"
}
}
export const validateNumber = ( val ) => {
if (!/^-?\d+(\.?\d+)?$/.test(val)) {
return "Value must be a number"
@@ -499,12 +512,41 @@ 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"
}
}
export const validateMaxLength = (val, max) => {
if (val.length > max) {
return "Value must be less than MaxLength"
}
}
export const validateMinLength = (val, min) => {
if (val.length < min) {
return "Value must be greater than MinLength"
}
}
// validation of parameters before execute
export const validateParam = (param, isXml) => {
let errors = []
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
let required = param.get("required")
let maximum = param.get("maximum")
let minimum = param.get("minimum")
let type = param.get("type")
let format = param.get("format")
let maxLength = param.get("maxLength")
let minLength = param.get("minLength")
/*
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
@@ -521,13 +563,40 @@ export const validateParam = (param, isXml) => {
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 (maxLength || maxLength === 0) {
let err = validateMaxLength(value, maxLength)
if (err) errors.push(err)
}
if (minLength) {
let err = validateMinLength(value, minLength)
if (err) errors.push(err)
}
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
errors.push("Required field is not provided")
return errors
}
if (maximum || maximum === 0) {
let err = validateMaximum(value, maximum)
if (err) errors.push(err)
}
if (minimum || minimum === 0) {
let err = validateMinimum(value, minimum)
if (err) errors.push(err)
}
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
errors.push(err)
} else if ( type === "boolean" ) {
@@ -650,3 +719,29 @@ export const shallowEqualKeys = (a,b, keys) => {
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) )
+14
View File
@@ -252,8 +252,11 @@
font-size: 16px;
display: flex;
flex: 0 3 auto;
align-items: center;
word-break: break-all;
padding: 0 10px;
@include text_code();
@@ -775,6 +778,17 @@
.response-content-type {
padding-top: 1em;
&.controls-accept-header {
select {
border-color: green;
}
small {
color: green;
font-size: .7em;
}
}
}
@keyframes blinker
+2 -1
View File
@@ -237,7 +237,8 @@ span
.prop-name
{
display: inline-block;
width: 100px;
margin-right: 1em;
width: 8em;
}
.prop-type
+116
View File
@@ -0,0 +1,116 @@
/* eslint-env mocha */
import React from "react"
import expect, { createSpy } from "expect"
import { shallow } from "enzyme"
import ModelExample from "components/model-example"
import ModelComponent from "components/model-wrapper"
describe("<ModelExample/>", function(){
// Given
let components = {
ModelWrapper: ModelComponent
}
let props = {
getComponent: (c) => {
return components[c]
},
specSelectors: {},
schema: {},
example: "{\"example\": \"value\"}",
isExecute: false,
getConfigs: () => ({
defaultModelRendering: "model",
defaultModelExpandDepth: 1
})
}
let exampleSelectedTestInputs = [
{ defaultModelRendering: "model", isExecute: true },
{ defaultModelRendering: "example", isExecute: true },
{ defaultModelRendering: "example", isExecute: false },
{ defaultModelRendering: "othervalue", isExecute: true },
{ defaultModelRendering: "othervalue", isExecute: false }
]
let modelSelectedTestInputs = [
{ defaultModelRendering: "model", isExecute: false }
]
it("renders model and example tabs", function(){
// When
let wrapper = shallow(<ModelExample {...props}/>)
// Then should render tabs
expect(wrapper.find("div > ul.tab").length).toEqual(1)
let tabs = wrapper.find("div > ul.tab").children()
expect(tabs.length).toEqual(2)
tabs.forEach((node) => {
expect(node.length).toEqual(1)
expect(node.name()).toEqual("li")
expect(node.hasClass("tabitem")).toEqual(true)
})
expect(tabs.at(0).text()).toEqual("Example Value")
expect(tabs.at(1).text()).toEqual("Model")
})
exampleSelectedTestInputs.forEach(function(testInputs) {
it("example tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
// When
props.isExecute = testInputs.isExecute
props.getConfigs = () => ({
defaultModelRendering: testInputs.defaultModelRendering,
defaultModelExpandDepth: 1
})
let wrapper = shallow(<ModelExample {...props}/>)
// Then
let tabs = wrapper.find("div > ul.tab").children()
let exampleTab = tabs.at(0)
expect(exampleTab.hasClass("active")).toEqual(true)
let modelTab = tabs.at(1)
expect(modelTab.hasClass("active")).toEqual(false)
expect(wrapper.find("div > div").length).toEqual(1)
expect(wrapper.find("div > div").text()).toEqual(props.example)
})
})
modelSelectedTestInputs.forEach(function(testInputs) {
it("model tab is selected if isExecute = " + testInputs.isExecute + " and defaultModelRendering = " + testInputs.defaultModelRendering, function(){
// When
props.isExecute = testInputs.isExecute
props.getConfigs = () => ({
defaultModelRendering: testInputs.defaultModelRendering,
defaultModelExpandDepth: 1
})
let wrapper = shallow(<ModelExample {...props}/>)
// Then
let tabs = wrapper.find("div > ul.tab").children()
let exampleTab = tabs.at(0)
expect(exampleTab.hasClass("active")).toEqual(false)
let modelTab = tabs.at(1)
expect(modelTab.hasClass("active")).toEqual(true)
expect(wrapper.find("div > div").length).toEqual(1)
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(1)
})
})
it("passes defaultModelExpandDepth to ModelComponent", function(){
// When
let expandDepth = 0
props.isExecute = false
props.getConfigs = () => ({
defaultModelRendering: "model",
defaultModelExpandDepth: expandDepth
})
let wrapper = shallow(<ModelExample {...props}/>)
// Then
expect(wrapper.find("div > div").find(ModelComponent).props().expandDepth).toBe(expandDepth)
})
})
+51
View File
@@ -0,0 +1,51 @@
/* eslint-env mocha */
import React from "react"
import expect, { createSpy } from "expect"
import { shallow } from "enzyme"
import { fromJS } from "immutable"
import Models from "components/models"
import ModelCollpase from "components/model-collapse"
import ModelComponent from "components/model-wrapper"
describe("<Models/>", function(){
// Given
let components = {
Collapse: ModelCollpase,
ModelWrapper: ModelComponent
}
let props = {
getComponent: (c) => {
return components[c]
},
specSelectors: {
definitions: function() {
return fromJS({
def1: {},
def2: {}
})
}
},
layoutSelectors: {
isShown: createSpy()
},
layoutActions: {},
getConfigs: () => ({
docExpansion: "list",
defaultModelExpandDepth: 0
})
}
it("passes defaultModelExpandDepth to ModelWrapper", function(){
// When
let wrapper = shallow(<Models {...props}/>)
// Then should render tabs
expect(wrapper.find("ModelCollapse").length).toEqual(1)
expect(wrapper.find("ModelComponent").length).toBeGreaterThan(0)
wrapper.find("ModelComponent").forEach((modelWrapper) => {
expect(modelWrapper.props().expandDepth).toBe(0)
})
})
})
+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": {
get: {
parameters: [
{ name: "one", value: 1},
{ name: "two", value: "duos"}
{ name: "one", in: "query", value: 1},
{ name: "two", in: "query", value: "duos"}
]
}
}
@@ -43,8 +43,8 @@ describe("spec plugin - selectors", function(){
// Then
expect(paramValues.toJS()).toEqual({
one: 1,
two: "duos"
"query.one": 1,
"query.two": "duos"
})
})
+332 -6
View File
@@ -1,7 +1,23 @@
/* eslint-env mocha */
import expect from "expect"
import { fromJS } from "immutable"
import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils"
import { fromJS, OrderedMap } from "immutable"
import {
mapToList,
validateMinLength,
validateMaxLength,
validateDateTime,
validateGuid,
validateNumber,
validateInteger,
validateParam,
validateFile,
validateMaximum,
validateMinimum,
fromJSOrdered,
getAcceptControllingResponse,
createDeepLinkPath,
escapeDeepLinkPath
} from "core/utils"
import win from "core/window"
describe("utils", function() {
@@ -72,6 +88,36 @@ describe("utils", function() {
})
describe("validateMaximum", function() {
let errorMessage = "Value must be less than Maximum"
it("doesn't return for valid input", function() {
expect(validateMaximum(9, 10)).toBeFalsy()
expect(validateMaximum(19, 20)).toBeFalsy()
})
it("returns a message for invalid input", function() {
expect(validateMaximum(1, 0)).toEqual(errorMessage)
expect(validateMaximum(10, 9)).toEqual(errorMessage)
expect(validateMaximum(20, 19)).toEqual(errorMessage)
})
})
describe("validateMinimum", function() {
let errorMessage = "Value must be greater than Minimum"
it("doesn't return for valid input", function() {
expect(validateMinimum(2, 1)).toBeFalsy()
expect(validateMinimum(20, 10)).toBeFalsy()
})
it("returns a message for invalid input", function() {
expect(validateMinimum(-1, 0)).toEqual(errorMessage)
expect(validateMinimum(1, 2)).toEqual(errorMessage)
expect(validateMinimum(10, 20)).toEqual(errorMessage)
})
})
describe("validateNumber", function() {
let errorMessage = "Value must be a number"
@@ -158,7 +204,7 @@ describe("utils", function() {
})
})
describe("validateFile", function() {
describe("validateFile", function() {
let errorMessage = "Value must be a file"
it("validates against objects which are instances of 'File'", function() {
@@ -171,6 +217,62 @@ 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("validateMaxLength", function() {
let errorMessage = "Value must be less than MaxLength"
it("doesn't return for valid guid", function() {
expect(validateMaxLength("a", 1)).toBeFalsy()
expect(validateMaxLength("abc", 5)).toBeFalsy()
})
it("returns a message for invalid input'", function() {
expect(validateMaxLength("abc", 0)).toEqual(errorMessage)
expect(validateMaxLength("abc", 1)).toEqual(errorMessage)
expect(validateMaxLength("abc", 2)).toEqual(errorMessage)
})
})
describe("validateMinLength", function() {
let errorMessage = "Value must be greater than MinLength"
it("doesn't return for valid guid", function() {
expect(validateMinLength("a", 1)).toBeFalsy()
expect(validateMinLength("abc", 2)).toBeFalsy()
})
it("returns a message for invalid input'", function() {
expect(validateMinLength("abc", 5)).toEqual(errorMessage)
expect(validateMinLength("abc", 8)).toEqual(errorMessage)
})
})
describe("validateParam", function() {
let param = null
let result = null
@@ -196,7 +298,7 @@ describe("utils", function() {
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
// valid string
// valid string
param = fromJS({
required: true,
type: "string",
@@ -204,6 +306,50 @@ describe("utils", function() {
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
// valid string with min and max length
param = fromJS({
required: true,
type: "string",
value: "test string",
maxLength: 50,
minLength: 1
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})
it("validates required strings with min and max length", function() {
// invalid string with max length
param = fromJS({
required: true,
type: "string",
value: "test string",
maxLength: 5
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be less than MaxLength"] )
// invalid string with max length 0
param = fromJS({
required: true,
type: "string",
value: "test string",
maxLength: 0
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be less than MaxLength"] )
// invalid string with min length
param = fromJS({
required: true,
type: "string",
value: "test string",
minLength: 50
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be greater than MinLength"] )
})
it("validates optional strings", function() {
@@ -458,14 +604,47 @@ describe("utils", function() {
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
// valid number
// valid number with min and max
param = fromJS({
required: true,
type: "number",
value: 10
value: 10,
minimum: 5,
maximum: 99
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
// valid negative number with min and max
param = fromJS({
required: true,
type: "number",
value: -10,
minimum: -50,
maximum: -5
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
// invalid number with maximum:0
param = fromJS({
required: true,
type: "number",
value: 1,
maximum: 0
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be less than Maximum"] )
// invalid number with minimum:0
param = fromJS({
required: true,
type: "number",
value: -10,
minimum: 0
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be greater than Minimum"] )
})
it("validates optional numbers", function() {
@@ -581,5 +760,152 @@ describe("utils", function() {
const result = fromJSOrdered(param).toJS()
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")
})
})
})