Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
165c1d7fcb | ||
|
|
b1c6584112 | ||
|
|
f3c3c5c340 | ||
|
|
90c3be0e24 | ||
|
|
75521f64d9 | ||
|
|
d02dc6eebc | ||
|
|
841dcaf2fb | ||
|
|
4c2a6f452e | ||
|
|
4fb43fc886 | ||
|
|
2fb04c286b | ||
|
|
21100a0a8b | ||
|
|
40a8376a4f | ||
|
|
064bebe222 | ||
|
|
7f01d05ed7 | ||
|
|
b762a2f623 | ||
|
|
2ffb44e052 | ||
|
|
ff16ecd99a | ||
|
|
23c2682311 | ||
|
|
538a5dbd0e | ||
|
|
9549bf3c2b | ||
|
|
4536ebaf3b | ||
|
|
7e7444bc86 | ||
|
|
55e4a12502 | ||
|
|
ed08d9fb88 | ||
|
|
c0a700346b | ||
|
|
ab960e8c45 | ||
|
|
13deee49f8 | ||
|
|
e831fba297 | ||
|
|
a536a00d35 | ||
|
|
9e6e660a93 | ||
|
|
0e4d04650d | ||
|
|
62785d11ad | ||
|
|
d6d32267fe | ||
|
|
afcb7d3e82 | ||
|
|
7a86c1bf40 | ||
|
|
01ae2f5605 | ||
|
|
ebe9f9b7f4 | ||
|
|
344f28bf22 | ||
|
|
556ff037dc | ||
|
|
754a93c14e | ||
|
|
eccc26da1b | ||
|
|
99600df0f1 | ||
|
|
1cab4984e0 | ||
|
|
acff34e1d4 | ||
|
|
129129be97 | ||
|
|
4a6716ffed | ||
|
|
00745bca38 | ||
|
|
1bd1190749 | ||
|
|
667976ca67 | ||
|
|
0345f66ee2 | ||
|
|
7d24a95d78 | ||
|
|
ce16666b57 | ||
|
|
3cfda13cfe | ||
|
|
a54d6fa2bc | ||
|
|
c24a07c523 | ||
|
|
db57ee0dfe | ||
|
|
99a525eac2 | ||
|
|
3e71861712 | ||
|
|
5f8ffb870c | ||
|
|
3311f3e95f | ||
|
|
b5b00953e9 | ||
|
|
873cb2892f | ||
|
|
df149c543b | ||
|
|
d6d5b1d06e | ||
|
|
234e6d5d57 | ||
|
|
212396f24d | ||
|
|
f4a253461e | ||
|
|
f23b7044c8 | ||
|
|
d043f0e7af | ||
|
|
72cbcc69e8 | ||
|
|
e3fa724f87 | ||
|
|
811a0a10e3 | ||
|
|
0ab6fde25f | ||
|
|
99c03cf3bb | ||
|
|
071307c61e | ||
|
|
08c691894d | ||
|
|
b3e476f476 | ||
|
|
8ef7818f56 | ||
|
|
c5a23e584c | ||
|
|
f6e921f101 | ||
|
|
6defee4402 | ||
|
|
d980982942 | ||
|
|
30686d6975 | ||
|
|
07076d6064 | ||
|
|
5e6103f0cb | ||
|
|
5a1f824c21 | ||
|
|
284f187253 | ||
|
|
531e5d1d73 | ||
|
|
60a9dc490f | ||
|
|
ee2e82390b | ||
|
|
1dedd44324 | ||
|
|
bbf93c5e1f | ||
|
|
e2b2055b4b | ||
|
|
36b263e230 | ||
|
|
e7975e7f3d | ||
|
|
a9d4f5efde | ||
|
|
3189e6101b | ||
|
|
8919661438 | ||
|
|
e8d84c02e6 | ||
|
|
4f7e75f443 | ||
|
|
2d0c660d9f | ||
|
|
4038b11d69 | ||
|
|
97ab51c354 | ||
|
|
0fdaeff5e8 | ||
|
|
36aa568f0e | ||
|
|
c05b66f4d4 | ||
|
|
68974a95b2 | ||
|
|
c03210e7d4 | ||
|
|
e5a9571a72 | ||
|
|
58acaf681d | ||
|
|
78af4e7f9f | ||
|
|
e3f872ad63 | ||
|
|
58797025c6 | ||
|
|
12dd90f748 | ||
|
|
09148e478c | ||
|
|
a857e947de | ||
|
|
438546f923 | ||
|
|
ea66055329 | ||
|
|
2257836114 | ||
|
|
563a5643e7 | ||
|
|
af2c890e51 | ||
|
|
eed62339b2 | ||
|
|
eec04f4ce2 | ||
|
|
58422825c9 | ||
|
|
5952bb6cbf | ||
|
|
b4cb0ce247 | ||
|
|
19f7668b48 | ||
|
|
20e7c0708a | ||
|
|
f862caa599 | ||
|
|
c471f59c53 | ||
|
|
9a08904574 | ||
|
|
bec97cfaf5 | ||
|
|
6ccd037197 | ||
|
|
af2b1e20f1 | ||
|
|
23b1a8aabd | ||
|
|
a2eed69ee7 | ||
|
|
eb929d3129 | ||
|
|
5b7673590a | ||
|
|
6ae7eb4591 | ||
|
|
df47e0e956 | ||
|
|
5752ffcdab | ||
|
|
2bc6c45f83 | ||
|
|
01124b07ad | ||
|
|
1280abe737 | ||
|
|
f4d1d28dd8 | ||
|
|
4dc966870d | ||
|
|
1d07a4b764 | ||
|
|
65a4f9aaf2 | ||
|
|
fa01f2b45d | ||
|
|
1b7d94a54b | ||
|
|
f583469876 | ||
|
|
b242917e3e | ||
|
|
d1c1b000bf | ||
|
|
fdcdb831eb | ||
|
|
8eb5461664 | ||
|
|
676fd99960 | ||
|
|
adc09b6d5d | ||
|
|
ed364d3562 | ||
|
|
49705f3441 | ||
|
|
78fcf5f0ff | ||
|
|
5eb006ee3d | ||
|
|
5f2eaffbc3 | ||
|
|
0ea14189c0 | ||
|
|
914f6991cd | ||
|
|
88df65533c | ||
|
|
8340f5d06c | ||
|
|
6bced2ad48 | ||
|
|
2fd9d9ed25 | ||
|
|
20d9161e2b | ||
|
|
39501c8d82 | ||
|
|
d68dd5f7d6 | ||
|
|
2567e5168d | ||
|
|
bf6681c914 | ||
|
|
b9dbfccb8e | ||
|
|
b23c999d01 | ||
|
|
41d8089d0e | ||
|
|
c5d2faa3a2 | ||
|
|
df4ea9b3d6 | ||
|
|
62cb9ec581 | ||
|
|
494b99ebef | ||
|
|
1db8e498b7 | ||
|
|
918e0e46c0 | ||
|
|
760d1eba80 | ||
|
|
a2a2f76199 | ||
|
|
d5b9552a5a | ||
|
|
753134ec49 | ||
|
|
612078ac8c | ||
|
|
e45570b6c8 | ||
|
|
daef38d2e3 | ||
|
|
eb8a64a66f | ||
|
|
edfe88d299 | ||
|
|
c66436e7d5 | ||
|
|
b530ac8593 | ||
|
|
d30b3a9ba1 | ||
|
|
e326a99001 | ||
|
|
a28dc13191 | ||
|
|
c942f382fb | ||
|
|
b6bb1deab8 | ||
|
|
6224617984 | ||
|
|
b85d9a8c24 | ||
|
|
b28a649457 | ||
|
|
bb6bc00012 | ||
|
|
f235430f30 | ||
|
|
0c7119e855 | ||
|
|
d64e920665 | ||
|
|
c81fdaec57 | ||
|
|
960a99a5ea | ||
|
|
e74989f22e | ||
|
|
73ed923e28 | ||
|
|
599b448f91 | ||
|
|
6e40d04741 | ||
|
|
e80b2f5b3f | ||
|
|
32cd6fe09c | ||
|
|
8aebea34c4 | ||
|
|
5f6320e754 | ||
|
|
5574a6cb1f | ||
|
|
bb2e75da8f | ||
|
|
ee3669312a | ||
|
|
c81f51f696 | ||
|
|
bd44c2161a | ||
|
|
e2003ae922 | ||
|
|
0ac0b5ba32 | ||
|
|
f8381bf907 | ||
|
|
d378d38c12 | ||
|
|
53986d60bc | ||
|
|
5b6f27c7db | ||
|
|
47b495b24d | ||
|
|
496062f980 | ||
|
|
a920e3ab69 | ||
|
|
14e9fd7b0f | ||
|
|
ac4ef3fdd4 | ||
|
|
2de7b957df | ||
|
|
ef1ff15c89 |
@@ -5,6 +5,7 @@
|
||||
"stage-0"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-runtime",
|
||||
[
|
||||
"module-alias",
|
||||
[
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"rules": {
|
||||
"semi": [2, "never"],
|
||||
"strict": 0,
|
||||
"quotes": 2,
|
||||
"quotes": [2, "double", { "allowTemplateLiterals": true }],
|
||||
"no-unused-vars": 2,
|
||||
"no-multi-spaces": 1,
|
||||
"camelcase": 1,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
docker-run.sh text eol=lf
|
||||
+2
-1
@@ -2,5 +2,6 @@ node_modules
|
||||
.idea
|
||||
.deps_check
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
npm-debug.log*
|
||||
.eslintcache
|
||||
package-lock.json
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.4
|
||||
FROM alpine:3.5
|
||||
|
||||
MAINTAINER fehguy
|
||||
|
||||
|
||||
@@ -6,8 +6,15 @@
|
||||
|
||||
**This is the new version of swagger-ui, 3.x. Want to learn more? Check out our [FAQ](http://swagger.io/new-ui-faq/).**
|
||||
|
||||
**👉🏼 Want to score an easy open-source contribution?** Check out our [Good first contribution](https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+contribution%22) label.
|
||||
|
||||
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:
|
||||
|
||||
* [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.
|
||||
|
||||
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||
|
||||
## Compatibility
|
||||
@@ -15,7 +22,7 @@ The OpenAPI Specification has undergone 4 revisions since initial creation in 20
|
||||
|
||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status
|
||||
------------------ | ------------ | -------------------------- | ----- | ------
|
||||
3.0.9 | 2017-03-19 | 2.0 | [tag v3.0.9](https://github.com/swagger-api/swagger-ui/tree/v3.0.9) |
|
||||
3.0.17 | 2017-06-23 | 2.0 | [tag v3.0.17](https://github.com/swagger-api/swagger-ui/tree/v3.0.17) |
|
||||
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.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) |
|
||||
@@ -35,13 +42,21 @@ docker run -p 80:8080 swaggerapi/swagger-ui
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
##### Prerequisites
|
||||
- Node 6.x
|
||||
- NPM 3.x
|
||||
|
||||
If you just want to see your specs, open `dist/index.html` in your browser directly from your filesystem.
|
||||
|
||||
If you'd like to make modifications to the codebase, run the dev server with: `npm run dev`.
|
||||
If you'd like to make modifications to the codebase, run the dev server with: `npm run dev`. A development server will open on `3200`.
|
||||
|
||||
If you'd like to rebuild the `/dist` folder with your codebase changes, run `npm run build`.
|
||||
|
||||
##### Browser support
|
||||
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
|
||||
@@ -57,6 +72,11 @@ To help with the migration, here are the currently known issues with 3.X. This l
|
||||
- l10n (translations) is not implemented.
|
||||
- Relative path support for external files is not implemented.
|
||||
|
||||
### Direct use of JS and CSS assets
|
||||
To include the JS, CSS and image assets directly into a webpage, use the [swagger-ui-dist](https://www.npmjs.com/package/swagger-ui-dist) package.
|
||||
The root directory of this package contains the contents of the _dist/_ directory of this repo.
|
||||
As a node module, `swagger-ui-dist` also exports the `swagger-ui-bundle` and `swagger-ui-standalone-preset` objects.
|
||||
|
||||
### SwaggerUIBundle
|
||||
To use swagger-ui's bundles, you should take a look at the [source of swagger-ui html page](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html) and customize it. This basically requires you to instantiate a SwaggerUi object as below:
|
||||
|
||||
@@ -75,6 +95,33 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui
|
||||
})
|
||||
```
|
||||
|
||||
#### OAuth2 configuration
|
||||
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
|
||||
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`.
|
||||
|
||||
Config Name | Description
|
||||
--- | ---
|
||||
client_id | Default clientId. MUST be a string
|
||||
client_secret | Default clientSecret. MUST be a string
|
||||
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl` . MUST be a string
|
||||
appName | application name, displayed in authorization popup. MUST be a string
|
||||
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
|
||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||
|
||||
```
|
||||
const ui = SwaggerUIBundle({...})
|
||||
|
||||
// Method can be called in any place after calling constructor SwaggerUIBundle
|
||||
ui.initOAuth({
|
||||
clientId: "your-client-id",
|
||||
clientSecret: "your-client-secret-if-required",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name",
|
||||
scopeSeparator: " ",
|
||||
additionalQueryStringParams: {test: "hello"}
|
||||
})
|
||||
```
|
||||
|
||||
If you'd like to use the bundle files via npm, check out the [`swagger-ui-dist` package](https://www.npmjs.com/package/swagger-ui-dist).
|
||||
|
||||
#### Parameters
|
||||
@@ -88,6 +135,10 @@ dom_id | The id of a dom element inside which SwaggerUi will put the user interf
|
||||
oauth2RedirectUrl | OAuth redirect URL
|
||||
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||
configUrl | Configs URL
|
||||
parameterMacro | MUST be a function. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||
modelPropertyMacro | MUST be a function. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||
docExpansion | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). The default is 'list'.
|
||||
displayOperationId | Controls the display of operationId in operations list. The default is `false`.
|
||||
|
||||
### Plugins
|
||||
|
||||
@@ -107,9 +158,9 @@ let preset = [
|
||||
```
|
||||
|
||||
#### Configs plugin
|
||||
Configs plugin allows to fetch external configs instead of passing them to `SwaggerUIBundle`. Fetched configs support two formats: JSON or yaml. The plugin is enabled by default.
|
||||
Configs plugin allows to fetch external configs instead of passing them to `SwaggerUIBundle`. Fetched configs support two formats: JSON or yaml. The plugin is enabled by default.
|
||||
There are three options of passing config:
|
||||
- add a query parameter `config` with URL to a server where the configs are hosted. For ex. http://petstore.swagger.io/?configs=http://localhost:3001/config.yaml
|
||||
- add a query parameter `config` with URL to a server where the configs are hosted. For ex. http://petstore.swagger.io/?config=http://localhost:3001/config.yaml
|
||||
- add a config `configUrl` with URL to SwaggerUIBundle
|
||||
- change default configs in `swagger-config.yaml` *Note: after changing, the project must be re-built*
|
||||
|
||||
|
||||
@@ -88,6 +88,15 @@ window.onload = function() {
|
||||
})
|
||||
|
||||
window.ui = ui
|
||||
|
||||
ui.initOAuth({
|
||||
clientId: "your-client-id",
|
||||
clientSecret: "your-client-secret-if-required",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name",
|
||||
scopeSeparator: " ",
|
||||
additionalQueryStringParams: {}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
qp = (window.location.hash || location.search).substring(1);
|
||||
@@ -35,7 +36,7 @@
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback(oauth2.auth);
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
@@ -45,9 +46,8 @@
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid});
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Vendored
+3
-3
@@ -8,6 +8,7 @@
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
qp = (window.location.hash || location.search).substring(1);
|
||||
@@ -35,7 +36,7 @@
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback(oauth2.auth);
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
@@ -45,9 +46,8 @@
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid});
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Vendored
+40
-41
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;AAu/FA;AA6+FA;;;;;;;;;;;;;;;;;;;;;;;;;;AAoTA;;;;;;AAoIA;AAi7FA;AAmtCA;AAi0IA;AA2pJA;AA+uFA;AA2rGA;AAgiFA;AA0rFA;AAk9CA;AA2hDA;AA4rCA;AAg6EA;;;;;AA4gCA;AA02JA;;;;;;;;;;;;;;AAuyEA;AA4mIA;AAquJA;AAwsHA;AA2mGA;AAiiEA;AAq4DA;AA+2DA;AAmfA;;;;;;AAmrFA;AA62FA;;;;;AAy3CA;AA2qFA;AAw2CA;AAqkCA;AA++CA;AAsiFA;AAk2FA;;;;;;;;;AAm/CA;AA2zIA;AAk4DA;AAolDA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AAitFA;;;;;;AAoIA;AAy2FA;AA8iCA;AA6lJA;AA8vIA;AA8iFA;AAi4GA;AA8jFA;AAu0FA;AA89CA;AAy9CA;AA+qCA;AAs0EA;;;;;AAw/CA;AA8zJA;;;;;;;;;;;;;;AAyoFA;AA+lIA;AA4oJA;AAqvHA;AAsvGA;AA2iEA;AAy5DA;AA65DA;AAAA;;;;;;AAk8GA;AA2nHA;;;;;AAkoDA;AAgsFA;AA6kDA;AAq3CA;AA4wFA;AAk3CA;AA8iFA;;;;;;;;;AA2qEA;AA2zIA;AAu7FA;AAmrFA;AAwiHA","sourceRoot":""}
|
||||
Vendored
+11
-10
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA8QA;AAitGA;AA+vFA;;;;;;AA6eA;AAkvFA;AAu+CA;AAo+CA;AAgrCA;AAgyEA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;AA+uFA;;;;;AAyOA;AAo7GA;AAw0FA;;;;;;AAmZA;AAivFA;AAu+CA;AAo+CA;AAirCA;AAuyEA","sourceRoot":""}
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+9
-9
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAyxCA;AAoyHA;AAuxHA;AAy4FA;AA2sCA;AAmgCA;AA0iCA;AA64BA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;AAylFA;;;;;;AAg5CA;AA2pHA;AA6qIA;AAi+FA;AAyvDA;AAmzCA;AA+xCA","sourceRoot":""}
|
||||
+6
-3
@@ -2,7 +2,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
INDEX_FILE=/usr/share/nginx/html/index.html
|
||||
NGINX_ROOT=/usr/share/nginx/html
|
||||
INDEX_FILE=$NGINX_ROOT/index.html
|
||||
|
||||
replace_in_index () {
|
||||
if [ "$1" != "**None**" ]; then
|
||||
@@ -30,8 +31,10 @@ if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
|
||||
fi
|
||||
|
||||
if [[ -f $SWAGGER_JSON ]]; then
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|swagger.json|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|swagger.json|g" $INDEX_FILE
|
||||
cp $SWAGGER_JSON $NGINX_ROOT
|
||||
REL_PATH="/$(basename $SWAGGER_JSON)"
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
|
||||
else
|
||||
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$API_URL|g" $INDEX_FILE
|
||||
sed -i "s|http://example.com/api|$API_URL|g" $INDEX_FILE
|
||||
|
||||
+12
-2
@@ -9,7 +9,17 @@ const {gitDescribeSync} = require('git-describe');
|
||||
var loadersByExtension = require('./build-tools/loadersByExtension')
|
||||
|
||||
var pkg = require('./package.json')
|
||||
const gitInfo = gitDescribeSync(__dirname)
|
||||
|
||||
let gitInfo
|
||||
|
||||
try {
|
||||
gitInfo = gitDescribeSync(__dirname)
|
||||
} catch(e) {
|
||||
gitInfo = {
|
||||
hash: 'noGit',
|
||||
dirty: false
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(options) {
|
||||
|
||||
@@ -137,7 +147,7 @@ module.exports = function(options) {
|
||||
extensions: ["", ".web.js", ".js", ".jsx", ".json", ".less"],
|
||||
packageAlias: 'browser',
|
||||
alias: {
|
||||
base: "getbase/src/less/base"
|
||||
base: "getbase/src/less/base",
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
+8
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.0.9",
|
||||
"version": "3.0.17",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -19,7 +19,7 @@
|
||||
"build-core": "webpack --config webpack-dist.config.js --colors",
|
||||
"build-standalone": "webpack --config webpack-dist-standalone.config.js --colors",
|
||||
"predev": "npm install",
|
||||
"dev": "npm-run-all --parallel hot-server watch open-localhost",
|
||||
"dev": "npm-run-all --parallel hot-server open-localhost",
|
||||
"watch": "webpack --config webpack-watch.config.js --watch --progress",
|
||||
"open-localhost": "node -e 'require(\"open\")(\"http://localhost:3200\")'",
|
||||
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/",
|
||||
@@ -32,10 +32,9 @@
|
||||
"test": "npm run lint-errors && npm run just-test-in-node",
|
||||
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
||||
"just-test": "karma start --config karma.conf.js",
|
||||
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components"
|
||||
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"base64-js": "^1.2.0",
|
||||
"brace": "0.7.0",
|
||||
"deep-extend": "0.4.1",
|
||||
@@ -67,14 +66,15 @@
|
||||
"redux-immutable": "3.0.8",
|
||||
"redux-logger": "*",
|
||||
"reselect": "2.5.3",
|
||||
"sanitize-html": "^1.14.1",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.0.9",
|
||||
"swagger-client": "3.0.16",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
"xml": "1.0.1",
|
||||
"yaml-js": "^0.1.3"
|
||||
"yaml-js": "0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "6.6.1",
|
||||
@@ -82,6 +82,7 @@
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-loader": "^6.3.2",
|
||||
"babel-plugin-module-alias": "^1.6.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"babel-preset-es2015-ie": "^6.6.2",
|
||||
"babel-preset-react": "^6.23.0",
|
||||
@@ -131,7 +132,7 @@
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"IE 10"
|
||||
"IE 11"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"webpack-dev-server": "1.14.0"
|
||||
|
||||
@@ -53,8 +53,7 @@ export default class ApiKeyAuth extends React.Component {
|
||||
<h4>Api key authorization<JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
||||
{ value && <h6>Authorized</h6>}
|
||||
<Row>
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={ schema.get("description") } />
|
||||
<Markdown source={ schema.get("description") } />
|
||||
</Row>
|
||||
<Row>
|
||||
<p>Name: <code>{ schema.get("name") }</code></p>
|
||||
|
||||
@@ -59,8 +59,7 @@ export default class BasicAuth extends React.Component {
|
||||
<h4>Basic authorization<JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
||||
{ username && <h6>Authorized</h6> }
|
||||
<Row>
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={ schema.get("description") } />
|
||||
<Markdown source={ schema.get("description") } />
|
||||
</Row>
|
||||
<Row>
|
||||
<label>Username:</label>
|
||||
|
||||
@@ -21,14 +21,16 @@ export default class Oauth2 extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
let { name, schema, authorized } = this.props
|
||||
let { name, schema, authorized, authSelectors } = this.props
|
||||
let auth = authorized && authorized.get(name)
|
||||
let authConfigs = authSelectors.getConfigs() || {}
|
||||
let username = auth && auth.get("username") || ""
|
||||
let clientId = auth && auth.get("clientId") || ""
|
||||
let clientSecret = auth && auth.get("clientSecret") || ""
|
||||
let passwordType = auth && auth.get("passwordType") || "basic"
|
||||
let clientId = auth && auth.get("clientId") || authConfigs.clientId || ""
|
||||
let clientSecret = auth && auth.get("clientSecret") || authConfigs.clientSecret || ""
|
||||
let passwordType = auth && auth.get("passwordType") || "request-body"
|
||||
|
||||
this.state = {
|
||||
appName: authConfigs.appName,
|
||||
name: name,
|
||||
schema: schema,
|
||||
scopes: [],
|
||||
@@ -41,11 +43,12 @@ export default class Oauth2 extends React.Component {
|
||||
}
|
||||
|
||||
authorize =() => {
|
||||
let { authActions, errActions, getConfigs } = this.props
|
||||
let { authActions, errActions, getConfigs, authSelectors } = this.props
|
||||
let configs = getConfigs()
|
||||
let authConfigs = authSelectors.getConfigs()
|
||||
|
||||
errActions.clear({authId: name,type: "auth", source: "auth"})
|
||||
oauth2Authorize(this.state, authActions, errActions, configs)
|
||||
oauth2Authorize({auth: this.state, authActions, errActions, configs, authConfigs })
|
||||
}
|
||||
|
||||
onScopeChange =(e) => {
|
||||
@@ -94,12 +97,13 @@ export default class Oauth2 extends React.Component {
|
||||
let isAuthorized = !!authorizedAuth
|
||||
let errors = errSelectors.allErrors().filter( err => err.get("authId") === name)
|
||||
let isValid = !errors.filter( err => err.get("source") === "validation").size
|
||||
let description = schema.get("description")
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>OAuth2.0 <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={ schema.get("description") } />
|
||||
{ !this.state.appName ? null : <h5>Application: { this.state.appName } </h5> }
|
||||
{ description && <Markdown source={ schema.get("description") } /> }
|
||||
|
||||
{ isAuthorized && <h6>Authorized</h6> }
|
||||
|
||||
@@ -137,8 +141,8 @@ export default class Oauth2 extends React.Component {
|
||||
isAuthorized ? <code> { this.state.passwordType } </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<select id="password_type" data-name="passwordType" onChange={ this.onInputChange }>
|
||||
<option value="basic">Basic auth</option>
|
||||
<option value="request-body">Request body</option>
|
||||
<option value="basic">Basic auth</option>
|
||||
<option value="query">Query parameters</option>
|
||||
</select>
|
||||
</Col>
|
||||
@@ -153,7 +157,11 @@ export default class Oauth2 extends React.Component {
|
||||
{
|
||||
isAuthorized ? <code> ****** </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="client_id" type="text" required={ flow === PASSWORD } data-name="clientId"
|
||||
<input id="client_id"
|
||||
type="text"
|
||||
required={ flow === PASSWORD }
|
||||
value={ this.state.clientId }
|
||||
data-name="clientId"
|
||||
onChange={ this.onInputChange }/>
|
||||
</Col>
|
||||
}
|
||||
@@ -166,7 +174,10 @@ export default class Oauth2 extends React.Component {
|
||||
{
|
||||
isAuthorized ? <code> ****** </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="client_secret" type="text" data-name="clientSecret"
|
||||
<input id="client_secret"
|
||||
value={ this.state.clientSecret }
|
||||
type="text"
|
||||
data-name="clientSecret"
|
||||
onChange={ this.onInputChange }/>
|
||||
</Col>
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class Curl extends React.Component {
|
||||
<div>
|
||||
<h4>Curl</h4>
|
||||
<div className="copy-paste">
|
||||
<textarea onFocus={this.handleFocus} className="curl" style={{ whiteSpace: "normal" }} value={curl}></textarea>
|
||||
<textarea onFocus={this.handleFocus} readOnly="true" className="curl" style={{ whiteSpace: "normal" }} value={curl}></textarea>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,14 +5,18 @@ import Collapse from "react-collapse"
|
||||
export default class Errors extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
jumpToLine: PropTypes.func,
|
||||
editorActions: PropTypes.object,
|
||||
errSelectors: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
let { jumpToLine, errSelectors, layoutSelectors, layoutActions } = this.props
|
||||
let { editorActions, errSelectors, layoutSelectors, layoutActions } = this.props
|
||||
|
||||
if(editorActions && editorActions.jumpToLine) {
|
||||
var jumpToLine = editorActions.jumpToLine
|
||||
}
|
||||
|
||||
let errors = errSelectors.allErrors()
|
||||
|
||||
@@ -37,10 +41,11 @@ export default class Errors extends React.Component {
|
||||
<Collapse isOpened={ isVisible } animated >
|
||||
<div className="errors">
|
||||
{ sortedJSErrors.map((err, i) => {
|
||||
if(err.get("type") === "thrown") {
|
||||
let type = err.get("type")
|
||||
if(type === "thrown" || type === "auth") {
|
||||
return <ThrownErrorItem key={ i } error={ err.get("error") || err } jumpToLine={jumpToLine} />
|
||||
}
|
||||
if(err.get("type") === "spec") {
|
||||
if(type === "spec") {
|
||||
return <SpecErrorItem key={ i } error={ err } jumpToLine={jumpToLine} />
|
||||
}
|
||||
}) }
|
||||
@@ -95,7 +100,7 @@ const SpecErrorItem = ( { error, jumpToLine } ) => {
|
||||
<div>
|
||||
<h4>{ toTitleCase(error.get("source")) + " " + error.get("level") } { locationMessage }</h4>
|
||||
<span style={{ whiteSpace: "pre-line"}}>{ error.get("message") }</span>
|
||||
<div>
|
||||
<div style={{ "text-decoration": "underline", "cursor": "pointer" }}>
|
||||
{ jumpToLine ? (
|
||||
<a onClick={jumpToLine.bind(null, error.get("line"))}>Jump to line { error.get("line") }</a>
|
||||
) : null }
|
||||
|
||||
@@ -99,7 +99,7 @@ export default class Info extends React.Component {
|
||||
</hgroup>
|
||||
|
||||
<div className="description">
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} source={ description } />
|
||||
<Markdown source={ description } />
|
||||
</div>
|
||||
|
||||
{
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import React, { PropTypes } from "react"
|
||||
import OriCollapse from "react-collapse"
|
||||
import _Markdown from "react-remarkable"
|
||||
|
||||
function xclass(...args) {
|
||||
return args.filter(a => !!a).join(" ").trim()
|
||||
}
|
||||
|
||||
export const Markdown = _Markdown
|
||||
|
||||
export class Container extends React.Component {
|
||||
render() {
|
||||
let { fullscreen, full, ...rest } = this.props
|
||||
@@ -73,7 +70,7 @@ export class Col extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
let classes = xclass(rest.className, "clear", ...classesAr)
|
||||
let classes = xclass(rest.className, ...classesAr)
|
||||
|
||||
return (
|
||||
<section {...rest} style={{display: hide ? "none": null}} className={classes}/>
|
||||
|
||||
@@ -22,13 +22,14 @@ export default class LiveResponse extends React.Component {
|
||||
render() {
|
||||
const { request, response, getComponent } = this.props
|
||||
|
||||
const body = response.get("text")
|
||||
const status = response.get("status")
|
||||
const url = response.get("url")
|
||||
const headers = response.get("headers").toJS()
|
||||
const notDocumented = response.get("notDocumented")
|
||||
const isError = response.get("error")
|
||||
|
||||
const body = isError ? response.get("response").get("text") : response.get("text")
|
||||
|
||||
const headersKeys = Object.keys(headers)
|
||||
const contentType = headers["content-type"]
|
||||
|
||||
@@ -37,6 +38,7 @@ export default class LiveResponse extends React.Component {
|
||||
const returnObject = headersKeys.map(key => {
|
||||
return <span className="headerline" key={key}> {key}: {headers[key]} </span>
|
||||
})
|
||||
const hasHeaders = returnObject.length !== 0
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -54,28 +56,29 @@ export default class LiveResponse extends React.Component {
|
||||
<td className="col response-col_status">
|
||||
{ status }
|
||||
{
|
||||
!notDocumented ? null :
|
||||
<div className="response-undocumented">
|
||||
<i> Undocumented </i>
|
||||
</div>
|
||||
notDocumented ? <div className="response-undocumented">
|
||||
<i> Undocumented </i>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</td>
|
||||
<td className="col response-col_description">
|
||||
{
|
||||
!isError ? null : <span>
|
||||
{`${response.get("name")}: ${response.get("message")}`}
|
||||
</span>
|
||||
isError ? <span>
|
||||
{`${response.get("name")}: ${response.get("message")}`}
|
||||
</span>
|
||||
: null
|
||||
}
|
||||
{
|
||||
!body || isError ? null
|
||||
: <ResponseBody content={ body }
|
||||
contentType={ contentType }
|
||||
url={ url }
|
||||
headers={ headers }
|
||||
getComponent={ getComponent }/>
|
||||
body ? <ResponseBody content={ body }
|
||||
contentType={ contentType }
|
||||
url={ url }
|
||||
headers={ headers }
|
||||
getComponent={ getComponent }/>
|
||||
: null
|
||||
}
|
||||
{
|
||||
!headers ? null : <Headers headers={ returnObject }/>
|
||||
hasHeaders ? <Headers headers={ returnObject }/> : null
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -40,6 +40,7 @@ class ObjectModel extends Component {
|
||||
let additionalProperties = schema.get("additionalProperties")
|
||||
let title = schema.get("title") || name
|
||||
let required = schema.get("required")
|
||||
const Markdown = getComponent("Markdown")
|
||||
const JumpToPathSection = ({ name }) => <span className="model-jump-to-path"><JumpToPath path={`definitions.${name}`} /></span>
|
||||
let collapsedContent = (<span>
|
||||
<span>{ braceOpen }</span>...<span>{ braceClose }</span>
|
||||
@@ -66,7 +67,9 @@ class ObjectModel extends Component {
|
||||
{
|
||||
!description ? null : <tr style={{ color: "#999", fontStyle: "italic" }}>
|
||||
<td>description:</td>
|
||||
<td>{ description }</td>
|
||||
<td>
|
||||
<Markdown source={ description } />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
{
|
||||
@@ -114,11 +117,12 @@ class ObjectModel extends Component {
|
||||
class Primitive extends Component {
|
||||
static propTypes = {
|
||||
schema: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
required: PropTypes.bool
|
||||
}
|
||||
|
||||
render(){
|
||||
let { schema, required } = this.props
|
||||
let { schema, getComponent, required } = this.props
|
||||
|
||||
if(!schema || !schema.get) {
|
||||
// don't render if schema isn't correctly formed
|
||||
@@ -129,17 +133,23 @@ class Primitive extends Component {
|
||||
let format = schema.get("format")
|
||||
let xml = schema.get("xml")
|
||||
let enumArray = schema.get("enum")
|
||||
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "$$ref"].indexOf(key) === -1 )
|
||||
let description = schema.get("description")
|
||||
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
||||
let style = required ? { fontWeight: "bold" } : {}
|
||||
const Markdown = getComponent("Markdown")
|
||||
|
||||
return <span className="prop">
|
||||
<span className="prop-type" style={ style }>{ type }</span> { required && <span style={{ color: "red" }}>*</span>}
|
||||
{ format && <span className="prop-format">(${format})</span>}
|
||||
{
|
||||
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
|
||||
<br />{ key !== "description" && key + ": " }{ String(v) }</span>)
|
||||
<br />{ key }: { String(v) }</span>)
|
||||
: null
|
||||
}
|
||||
{
|
||||
!description ? null :
|
||||
<Markdown source={ description } />
|
||||
}
|
||||
{
|
||||
xml && xml.size ? (<span><br /><span style={ propStyle }>xml:</span>
|
||||
{
|
||||
@@ -217,7 +227,7 @@ class Model extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { schema, required, name, isRef } = this.props
|
||||
let { schema, getComponent, required, name, isRef } = this.props
|
||||
let $$ref = schema && schema.get("$$ref")
|
||||
let modelName = $$ref && this.getModelName( $$ref )
|
||||
let modelSchema, type
|
||||
@@ -236,7 +246,7 @@ class Model extends Component {
|
||||
switch(type) {
|
||||
case "object":
|
||||
return <ObjectModel className="object" { ...this.props } schema={ modelSchema }
|
||||
name={ modelName || name }
|
||||
name={ name || modelName }
|
||||
isRef={ isRef!== undefined ? isRef : !!$$ref }/>
|
||||
case "array":
|
||||
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } required={ required } />
|
||||
@@ -245,7 +255,7 @@ class Model extends Component {
|
||||
case "integer":
|
||||
case "boolean":
|
||||
default:
|
||||
return <Primitive schema={ modelSchema } required={ required }/>
|
||||
return <Primitive getComponent={ getComponent } schema={ modelSchema } required={ required }/>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ export default class Models extends Component {
|
||||
getComponent: PropTypes.func,
|
||||
specSelectors: PropTypes.object,
|
||||
layoutSelectors: PropTypes.object,
|
||||
layoutActions: PropTypes.object
|
||||
layoutActions: PropTypes.object,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render(){
|
||||
let { specSelectors, getComponent, layoutSelectors, layoutActions } = this.props
|
||||
let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
|
||||
let definitions = specSelectors.definitions()
|
||||
let showModels = layoutSelectors.isShown("models", true)
|
||||
let { docExpansion } = getConfigs()
|
||||
let showModels = layoutSelectors.isShown("models", docExpansion === "full" || docExpansion === "list" )
|
||||
|
||||
const Model = getComponent("model")
|
||||
const Collapse = getComponent("Collapse")
|
||||
|
||||
@@ -17,6 +17,8 @@ export default class Operation extends React.Component {
|
||||
|
||||
allowTryItOut: PropTypes.bool,
|
||||
|
||||
displayOperationId: PropTypes.bool,
|
||||
|
||||
response: PropTypes.object,
|
||||
request: PropTypes.object,
|
||||
|
||||
@@ -27,13 +29,15 @@ export default class Operation extends React.Component {
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
fn: PropTypes.object.isRequired
|
||||
fn: PropTypes.object.isRequired,
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
showSummary: true,
|
||||
response: null,
|
||||
allowTryItOut: true,
|
||||
displayOperationId: false,
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
@@ -76,8 +80,10 @@ export default class Operation extends React.Component {
|
||||
}
|
||||
|
||||
isShown =() => {
|
||||
let { layoutSelectors, isShownKey } = this.props
|
||||
return layoutSelectors.isShown(isShownKey, false ) // Here is where we set the default
|
||||
let { layoutSelectors, isShownKey, getConfigs } = this.props
|
||||
let { docExpansion } = getConfigs()
|
||||
|
||||
return layoutSelectors.isShown(isShownKey, docExpansion === "full" ) // Here is where we set the default
|
||||
}
|
||||
|
||||
onTryoutClick =() => {
|
||||
@@ -105,6 +111,7 @@ export default class Operation extends React.Component {
|
||||
response,
|
||||
request,
|
||||
allowTryItOut,
|
||||
displayOperationId,
|
||||
|
||||
fn,
|
||||
getComponent,
|
||||
@@ -123,6 +130,7 @@ export default class Operation extends React.Component {
|
||||
let produces = operation.get("produces")
|
||||
let schemes = operation.get("schemes")
|
||||
let parameters = getList(operation, ["parameters"])
|
||||
let operationId = operation.get("__originalOperationId")
|
||||
|
||||
const Responses = getComponent("responses")
|
||||
const Parameters = getComponent( "parameters" )
|
||||
@@ -159,6 +167,8 @@ export default class Operation extends React.Component {
|
||||
</div>
|
||||
}
|
||||
|
||||
{ displayOperationId && operationId ? <span className="opblock-summary-operation-id">{operationId}</span> : null }
|
||||
|
||||
{
|
||||
(!security || !security.count()) ? null :
|
||||
<AuthorizeOperationBtn authActions={ authActions }
|
||||
@@ -173,7 +183,7 @@ export default class Operation extends React.Component {
|
||||
{ description &&
|
||||
<div className="opblock-description-wrapper">
|
||||
<div className="opblock-description">
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} source={ description } />
|
||||
<Markdown source={ description } />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -10,10 +10,7 @@ export default class Operations extends React.Component {
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
authActions: PropTypes.object.isRequired,
|
||||
authSelectors: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
||||
getConfigs: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -25,6 +22,7 @@ export default class Operations extends React.Component {
|
||||
layoutActions,
|
||||
authActions,
|
||||
authSelectors,
|
||||
getConfigs,
|
||||
fn
|
||||
} = this.props
|
||||
|
||||
@@ -34,6 +32,7 @@ export default class Operations extends React.Component {
|
||||
const Collapse = getComponent("Collapse")
|
||||
|
||||
let showSummary = layoutSelectors.showSummary()
|
||||
let { docExpansion, displayOperationId } = getConfigs()
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -43,16 +42,15 @@ export default class Operations extends React.Component {
|
||||
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
||||
|
||||
let isShownKey = ["operations-tag", tag]
|
||||
let showTag = layoutSelectors.isShown(isShownKey, true)
|
||||
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||
|
||||
return (
|
||||
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}>
|
||||
|
||||
<h4 className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }>
|
||||
<span onClick={() => layoutActions.show(isShownKey, !showTag)}>{tag}</span>
|
||||
|
||||
<h4 onClick={() => layoutActions.show(isShownKey, !showTag)} className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }>
|
||||
<span>{tag}</span>
|
||||
{ !tagDescription ? null :
|
||||
<small onClick={() => layoutActions.show(isShownKey, !showTag)} >
|
||||
<small>
|
||||
{ tagDescription }
|
||||
</small>
|
||||
}
|
||||
@@ -88,6 +86,8 @@ export default class Operations extends React.Component {
|
||||
request={ request }
|
||||
allowTryItOut={allowTryItOut}
|
||||
|
||||
displayOperationId={displayOperationId}
|
||||
|
||||
specActions={ specActions }
|
||||
specSelectors={ specSelectors }
|
||||
|
||||
@@ -99,6 +99,7 @@ export default class Operations extends React.Component {
|
||||
|
||||
getComponent={ getComponent }
|
||||
fn={fn}
|
||||
getConfigs={ getConfigs }
|
||||
/>
|
||||
}).toArray()
|
||||
}
|
||||
|
||||
@@ -99,8 +99,7 @@ export default class ParameterRow extends Component {
|
||||
</td>
|
||||
|
||||
<td className="col parameters-col_description">
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={ param.get("description") }/>
|
||||
<Markdown source={ param.get("description") }/>
|
||||
{(isFormData && !isFormDataSupported) && <div>Error: your browser does not support FormData</div>}
|
||||
|
||||
{ bodyParam || !isExecute ? null
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Providers
|
||||
|
||||
Providers are generic bridges to third-party components. They provide two benefits:
|
||||
|
||||
1. ability for plugins to override third-party components, because providers are loaded through `getComponent`
|
||||
2. allows us to avoid painting ourselves into a corner with a third-party component
|
||||
@@ -0,0 +1,30 @@
|
||||
import React, { PropTypes } from "react"
|
||||
import Remarkable from "react-remarkable"
|
||||
import sanitize from "sanitize-html"
|
||||
|
||||
const sanitizeOptions = {
|
||||
textFilter: function(text) {
|
||||
return text
|
||||
.replace(/"/g, "\"")
|
||||
}
|
||||
}
|
||||
|
||||
function Markdown({ source }) {
|
||||
const sanitized = sanitize(source, sanitizeOptions)
|
||||
|
||||
// sometimes the sanitizer returns "undefined" as a string
|
||||
if(!source || !sanitized || sanitized === "undefined") {
|
||||
return null
|
||||
}
|
||||
|
||||
return <Remarkable
|
||||
options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
|
||||
source={sanitized}
|
||||
></Remarkable>
|
||||
}
|
||||
|
||||
Markdown.propTypes = {
|
||||
source: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default Markdown
|
||||
@@ -8,7 +8,7 @@ const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
||||
let exampleValue
|
||||
try {
|
||||
exampleValue = example && example.toJS ? example.toJS() : example
|
||||
exampleValue = JSON.stringify(exampleValue)
|
||||
exampleValue = JSON.stringify(exampleValue, null, 2)
|
||||
}
|
||||
catch(e) {
|
||||
exampleValue = String(example)
|
||||
@@ -76,7 +76,7 @@ export default class Response extends React.Component {
|
||||
<td className="col response-col_description">
|
||||
|
||||
<div className="response-col_description__inner">
|
||||
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} source={ response.get( "description" ) } />
|
||||
<Markdown source={ response.get( "description" ) } />
|
||||
</div>
|
||||
|
||||
{ example ? (
|
||||
|
||||
+8
-4
@@ -1,3 +1,5 @@
|
||||
import win from "./window"
|
||||
|
||||
export default function curl( request ){
|
||||
let curlified = []
|
||||
let type = ""
|
||||
@@ -18,11 +20,13 @@ export default function curl( request ){
|
||||
if ( request.get("body") ){
|
||||
|
||||
if(type === "multipart/form-data" && request.get("method") === "POST") {
|
||||
let formDataBody = request.get("body").split("&")
|
||||
|
||||
for(var data in formDataBody) {
|
||||
for( let [ k,v ] of request.get("body").values()) {
|
||||
curlified.push( "-F" )
|
||||
curlified.push(formDataBody[data])
|
||||
if (v instanceof win.File) {
|
||||
curlified.push( `"${k}=@${v.name};type=${v.type}"` )
|
||||
} else {
|
||||
curlified.push( `"${k}=${v}"` )
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curlified.push( "-d" )
|
||||
|
||||
+14
-6
@@ -4,8 +4,11 @@ import System from "core/system"
|
||||
import win from "core/window"
|
||||
import ApisPreset from "core/presets/apis"
|
||||
import * as AllPlugins from "core/plugins/all"
|
||||
import { filterConfigs } from "plugins/configs"
|
||||
import { parseSeach } from "core/utils"
|
||||
import { parseSeach, filterConfigs } from "core/utils"
|
||||
|
||||
const CONFIGS = [ "url", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion",
|
||||
"apisSorter", "operationsSorter", "supportedSubmitMethods", "dom_id", "defaultModelRendering", "oauth2RedirectUrl",
|
||||
"showRequestHeaders", "custom", "modelPropertyMacro", "parameterMacro", "displayOperationId" ]
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo
|
||||
@@ -21,9 +24,11 @@ module.exports = function SwaggerUI(opts) {
|
||||
spec: {},
|
||||
url: "",
|
||||
layout: "BaseLayout",
|
||||
docExpansion: "list",
|
||||
validatorUrl: "https://online.swagger.io/validator",
|
||||
configs: {
|
||||
},
|
||||
configs: {},
|
||||
custom: {},
|
||||
displayOperationId: false,
|
||||
|
||||
// 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.
|
||||
@@ -75,14 +80,16 @@ module.exports = function SwaggerUI(opts) {
|
||||
var system = store.getSystem()
|
||||
let queryConfig = parseSeach()
|
||||
|
||||
system.initOAuth = system.authActions.configureAuth
|
||||
|
||||
const downloadSpec = (fetchedConfig) => {
|
||||
if(typeof constructorConfig !== "object") {
|
||||
return system
|
||||
}
|
||||
|
||||
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
||||
let mergedConfig = deepExtend({}, constructorConfig, localConfig, fetchedConfig || {}, queryConfig)
|
||||
store.setConfigs(filterConfigs(mergedConfig))
|
||||
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
||||
store.setConfigs(filterConfigs(mergedConfig, CONFIGS))
|
||||
|
||||
if (fetchedConfig !== null) {
|
||||
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
||||
@@ -110,6 +117,7 @@ module.exports = function SwaggerUI(opts) {
|
||||
return downloadSpec()
|
||||
}
|
||||
|
||||
return system
|
||||
}
|
||||
|
||||
// Add presets
|
||||
|
||||
@@ -69,7 +69,7 @@ export class JsonSchema_string extends Component {
|
||||
return <Input type="file" className={ errors.length ? "invalid" : ""} onChange={ this.onChange } disabled={isDisabled}/>
|
||||
}
|
||||
else {
|
||||
return <Input type="text" className={ errors.length ? "invalid" : ""} value={value} placeholder={description} onChange={ this.onChange } disabled={isDisabled}/>
|
||||
return <Input type={ schema.format === "password" ? "password" : "text" } className={ errors.length ? "invalid" : ""} value={value} placeholder={description} onChange={ this.onChange } disabled={isDisabled}/>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
import win from "core/window"
|
||||
import { btoa } from "core/utils"
|
||||
|
||||
export default function authorize ( auth, authActions, errActions, configs ) {
|
||||
export default function authorize ( { auth, authActions, errActions, configs, authConfigs={} } ) {
|
||||
let { schema, scopes, name, clientId } = auth
|
||||
let flow = schema.get("flow")
|
||||
let query = []
|
||||
|
||||
switch (flow) {
|
||||
case "password":
|
||||
authActions.authorizePassword(auth)
|
||||
return
|
||||
|
||||
case "application":
|
||||
authActions.authorizeApplication(auth)
|
||||
return
|
||||
|
||||
case "accessCode":
|
||||
query.push("response_type=code")
|
||||
break
|
||||
|
||||
case "implicit":
|
||||
query.push("response_type=token")
|
||||
break
|
||||
}
|
||||
|
||||
if (typeof clientId === "string") {
|
||||
query.push("client_id=" + encodeURIComponent(clientId))
|
||||
}
|
||||
|
||||
let redirectUrl = configs.oauth2RedirectUrl
|
||||
let scopeSeparator = " "
|
||||
let state = btoa(new Date())
|
||||
let flow = schema.get("flow")
|
||||
let url
|
||||
|
||||
if (flow === "password") {
|
||||
authActions.authorizePassword(auth)
|
||||
return
|
||||
}
|
||||
|
||||
if (flow === "application") {
|
||||
authActions.authorizeApplication(auth)
|
||||
return
|
||||
}
|
||||
|
||||
// todo move to parser
|
||||
if ( !redirectUrl ) {
|
||||
if (typeof redirectUrl === "undefined") {
|
||||
errActions.newAuthErr( {
|
||||
authId: name,
|
||||
source: "validation",
|
||||
@@ -30,21 +40,38 @@ export default function authorize ( auth, authActions, errActions, configs ) {
|
||||
})
|
||||
return
|
||||
}
|
||||
query.push("redirect_uri=" + encodeURIComponent(redirectUrl))
|
||||
|
||||
if (flow === "implicit" || flow === "accessCode") {
|
||||
url = schema.get("authorizationUrl") + "?response_type=" + (flow === "implicit" ? "token" : "code")
|
||||
if (Array.isArray(scopes) && 0 < scopes.length) {
|
||||
let scopeSeparator = authConfigs.scopeSeparator || " "
|
||||
|
||||
query.push("scope=" + encodeURIComponent(scopes.join(scopeSeparator)))
|
||||
}
|
||||
|
||||
url += "&redirect_uri=" + encodeURIComponent(redirectUrl)
|
||||
+ "&scope=" + encodeURIComponent(scopes.join(scopeSeparator))
|
||||
+ "&state=" + encodeURIComponent(state)
|
||||
+ "&client_id=" + encodeURIComponent(clientId)
|
||||
let state = btoa(new Date())
|
||||
|
||||
query.push("state=" + encodeURIComponent(state))
|
||||
|
||||
if (typeof authConfigs.realm !== "undefined") {
|
||||
query.push("realm=" + encodeURIComponent(authConfigs.realm))
|
||||
}
|
||||
|
||||
let { additionalQueryStringParams } = authConfigs
|
||||
|
||||
for (let key in additionalQueryStringParams) {
|
||||
if (typeof additionalQueryStringParams[key] !== "undefined") {
|
||||
query.push([key, additionalQueryStringParams[key]].map(encodeURIComponent).join("="))
|
||||
}
|
||||
}
|
||||
|
||||
let url = [schema.get("authorizationUrl"), query.join("&")].join("?")
|
||||
|
||||
// pass action authorizeOauth2 and authentication data through window
|
||||
// to authorize with oauth2
|
||||
win.swaggerUIRedirectOauth2 = {
|
||||
auth: auth,
|
||||
state: state,
|
||||
redirectUrl: redirectUrl,
|
||||
callback: flow === "implicit" ? authActions.preAuthorizeImplicit : authActions.authorizeAccessCode,
|
||||
errCb: errActions.newAuthErr
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export const LOGOUT = "logout"
|
||||
export const PRE_AUTHORIZE_OAUTH2 = "pre_authorize_oauth2"
|
||||
export const AUTHORIZE_OAUTH2 = "authorize_oauth2"
|
||||
export const VALIDATE = "validate"
|
||||
export const CONFIGURE_AUTH = "configure_auth"
|
||||
|
||||
const scopeSeparator = " "
|
||||
|
||||
@@ -80,12 +81,17 @@ export const authorizePassword = ( auth ) => ( { authActions } ) => {
|
||||
if ( passwordType === "basic") {
|
||||
headers.Authorization = "Basic " + btoa(username + ":" + password)
|
||||
} else {
|
||||
Object.assign(form, {username}, {password})
|
||||
Object.assign(form, {username}, {password})
|
||||
|
||||
if ( passwordType === "query") {
|
||||
if ( clientId ) { query.client_id = clientId }
|
||||
if ( clientSecret ) { query.client_secret = clientSecret }
|
||||
if ( clientId ) {
|
||||
query.client_id = clientId
|
||||
}
|
||||
if ( clientSecret ) {
|
||||
query.client_secret = clientSecret
|
||||
}
|
||||
} else {
|
||||
Object.assign(form, {client_id: clientId}, {client_secret: clientSecret})
|
||||
headers.Authorization = "Basic " + btoa(clientId + ":" + clientSecret)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,31 +100,38 @@ export const authorizePassword = ( auth ) => ( { authActions } ) => {
|
||||
|
||||
export const authorizeApplication = ( auth ) => ( { authActions } ) => {
|
||||
let { schema, scopes, name, clientId, clientSecret } = auth
|
||||
let headers = {
|
||||
Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
|
||||
}
|
||||
let form = {
|
||||
grant_type: "client_credentials",
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
scope: scopes.join(scopeSeparator)
|
||||
}
|
||||
|
||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth })
|
||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers })
|
||||
}
|
||||
|
||||
export const authorizeAccessCode = ( auth ) => ( { authActions } ) => {
|
||||
let { schema, name, clientId, clientSecret } = auth
|
||||
let form = {
|
||||
grant_type: "authorization_code",
|
||||
code: auth.code,
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret
|
||||
}
|
||||
|
||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
|
||||
export const authorizeAccessCode = ( { auth, redirectUrl } ) => ( { authActions } ) => {
|
||||
let { schema, name, clientId, clientSecret } = auth
|
||||
let form = {
|
||||
grant_type: "authorization_code",
|
||||
code: auth.code,
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
redirect_uri: redirectUrl
|
||||
}
|
||||
|
||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
|
||||
}
|
||||
|
||||
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions } ) => {
|
||||
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => {
|
||||
let { body, query={}, headers={}, name, url, auth } = data
|
||||
let { additionalQueryStringParams } = authSelectors.getConfigs() || {}
|
||||
let fetchUrl = url
|
||||
|
||||
for (let key in additionalQueryStringParams) {
|
||||
url += "&" + key + "=" + encodeURIComponent(additionalQueryStringParams[key])
|
||||
}
|
||||
|
||||
let _headers = Object.assign({
|
||||
"Accept":"application/json, text/plain, */*",
|
||||
@@ -127,45 +140,53 @@ export const authorizeRequest = ( data ) => ( { fn, authActions, errActions } )
|
||||
}, headers)
|
||||
|
||||
fn.fetch({
|
||||
url: url,
|
||||
url: fetchUrl,
|
||||
method: "post",
|
||||
headers: _headers,
|
||||
query: query,
|
||||
body: body
|
||||
})
|
||||
.then(function (response) {
|
||||
let token = JSON.parse(response.data)
|
||||
let error = token && ( token.error || "" )
|
||||
let parseError = token && ( token.parseError || "" )
|
||||
.then(function (response) {
|
||||
let token = JSON.parse(response.data)
|
||||
let error = token && ( token.error || "" )
|
||||
let parseError = token && ( token.parseError || "" )
|
||||
|
||||
if ( !response.ok ) {
|
||||
errActions.newAuthErr( {
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: response.statusText
|
||||
} )
|
||||
return
|
||||
}
|
||||
|
||||
if ( error || parseError ) {
|
||||
errActions.newAuthErr({
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: JSON.stringify(token)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
authActions.authorizeOauth2({ auth, token})
|
||||
})
|
||||
.catch(e => {
|
||||
let err = new Error(e)
|
||||
if ( !response.ok ) {
|
||||
errActions.newAuthErr( {
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: err.message
|
||||
} ) })
|
||||
message: response.statusText
|
||||
} )
|
||||
return
|
||||
}
|
||||
|
||||
if ( error || parseError ) {
|
||||
errActions.newAuthErr({
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: JSON.stringify(token)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
authActions.authorizeOauth2({ auth, token})
|
||||
})
|
||||
.catch(e => {
|
||||
let err = new Error(e)
|
||||
errActions.newAuthErr( {
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: err.message
|
||||
} )
|
||||
})
|
||||
}
|
||||
|
||||
export function configureAuth(payload) {
|
||||
return {
|
||||
type: CONFIGURE_AUTH,
|
||||
payload: payload
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
SHOW_AUTH_POPUP,
|
||||
AUTHORIZE,
|
||||
AUTHORIZE_OAUTH2,
|
||||
LOGOUT
|
||||
LOGOUT,
|
||||
CONFIGURE_AUTH
|
||||
} from "./actions"
|
||||
|
||||
export default {
|
||||
@@ -57,5 +58,9 @@ export default {
|
||||
})
|
||||
|
||||
return state.set("authorized", result)
|
||||
},
|
||||
|
||||
[CONFIGURE_AUTH]: (state, { payload } ) =>{
|
||||
return state.set("configs", payload)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,3 +79,8 @@ export const isAuthorized = ( state, securities ) =>( { authSelectors } ) => {
|
||||
}).indexOf(false) === -1
|
||||
}).length
|
||||
}
|
||||
|
||||
export const getConfigs = createSelector(
|
||||
state,
|
||||
auth => auth.get( "configs" )
|
||||
)
|
||||
|
||||
@@ -77,7 +77,9 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
|
||||
return specActions.updateJsonSpec(json)
|
||||
}
|
||||
|
||||
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }}) => {
|
||||
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => {
|
||||
const { modelPropertyMacro, parameterMacro } = getConfigs()
|
||||
|
||||
if(typeof(json) === "undefined") {
|
||||
json = specSelectors.specJson()
|
||||
}
|
||||
@@ -89,7 +91,7 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
|
||||
|
||||
let specStr = specSelectors.specStr()
|
||||
|
||||
return resolve({fetch, spec: json, baseDoc: url})
|
||||
return resolve({fetch, spec: json, baseDoc: url, modelPropertyMacro, parameterMacro })
|
||||
.then( ({spec, errors}) => {
|
||||
errActions.clear({
|
||||
type: "thrown"
|
||||
@@ -186,16 +188,23 @@ export const logRequest = (req) => {
|
||||
// Actually fire the request via fn.execute
|
||||
// (For debugging) and ease of testing
|
||||
export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
|
||||
let { pathName, method } = req
|
||||
let { pathName, method, operation } = req
|
||||
|
||||
let op = operation.toJS()
|
||||
|
||||
// if url is relative, parseUrl makes it absolute by inferring from `window.location`
|
||||
req.contextUrl = parseUrl(specSelectors.url()).toString()
|
||||
|
||||
let parsedRequest = Object.assign({}, req)
|
||||
if ( pathName && method ) {
|
||||
parsedRequest.operationId = method.toLowerCase() + "-" + pathName
|
||||
|
||||
if(op && op.operationId) {
|
||||
req.operationId = op.operationId
|
||||
} else if(op && pathName && method) {
|
||||
req.operationId = fn.opId(op, pathName, method)
|
||||
}
|
||||
|
||||
let parsedRequest = Object.assign({}, req)
|
||||
parsedRequest = fn.buildRequest(parsedRequest)
|
||||
|
||||
specActions.setRequest(req.pathName, req.method, parsedRequest)
|
||||
|
||||
return fn.execute(req)
|
||||
|
||||
@@ -41,7 +41,7 @@ export default {
|
||||
[UPDATE_PARAM]: ( state, {payload} ) => {
|
||||
let { path, paramName, value, isXml } = payload
|
||||
return state.updateIn( [ "resolved", "paths", ...path, "parameters" ], fromJS([]), parameters => {
|
||||
let index = parameters.findIndex( p => p.get( "name" ) === paramName )
|
||||
const index = parameters.findIndex(p => p.get( "name" ) === paramName )
|
||||
if (!(value instanceof win.File)) {
|
||||
value = fromJSOrdered( value )
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ export const specResolved = createSelector(
|
||||
// Default Spec ( as an object )
|
||||
export const spec = state => {
|
||||
let res = specResolved(state)
|
||||
if(res.count() < 1)
|
||||
res = specJson(state)
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ module.exports = function({ configs }) {
|
||||
buildRequest: Swagger.buildRequest,
|
||||
execute: Swagger.execute,
|
||||
resolve: Swagger.resolve,
|
||||
serializeRes: Swagger.serializeRes
|
||||
serializeRes: Swagger.serializeRes,
|
||||
opId: Swagger.helpers.opId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ import Model from "core/components/model"
|
||||
import Models from "core/components/models"
|
||||
import TryItOutButton from "core/components/try-it-out-button"
|
||||
|
||||
import Markdown from "core/components/providers/markdown"
|
||||
|
||||
import BaseLayout from "core/components/layouts/base"
|
||||
|
||||
import * as LayoutUtils from "core/components/layout-utils"
|
||||
@@ -89,6 +91,7 @@ export default function() {
|
||||
model: Model,
|
||||
models: Models,
|
||||
TryItOutButton,
|
||||
Markdown,
|
||||
BaseLayout
|
||||
}
|
||||
}
|
||||
|
||||
+24
-6
@@ -1,12 +1,13 @@
|
||||
import Im from "immutable"
|
||||
import shallowEqual from "shallowequal"
|
||||
|
||||
import camelCase from "lodash/camelCase"
|
||||
import upperFirst from "lodash/upperFirst"
|
||||
import _memoize from "lodash/memoize"
|
||||
import find from "lodash/find"
|
||||
import some from "lodash/some"
|
||||
import eq from "lodash/eq"
|
||||
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
|
||||
import win from "./window"
|
||||
|
||||
const DEFAULT_REPONSE_KEY = "default"
|
||||
|
||||
@@ -34,6 +35,9 @@ export function fromJSOrdered (js) {
|
||||
if(isImmutable(js))
|
||||
return js // Can't do much here
|
||||
|
||||
if (js instanceof win.File)
|
||||
return js
|
||||
|
||||
return !isObject(js) ? js :
|
||||
Array.isArray(js) ?
|
||||
Im.Seq(js).map(fromJSOrdered).toList() :
|
||||
@@ -414,11 +418,6 @@ export function pascalCaseFilename(filename) {
|
||||
return pascalCase(filename.replace(/\.[^./]*$/, ""))
|
||||
}
|
||||
|
||||
// Only compare a set of props
|
||||
export function shallowEqualKeys(a,b, keys) {
|
||||
return !!keys.find(key => !shallowEqual(a[key], b[key]))
|
||||
}
|
||||
|
||||
// Check if ...
|
||||
// - new props
|
||||
// - If immutable, use .is()
|
||||
@@ -577,3 +576,22 @@ export const buildFormData = (data) => {
|
||||
}
|
||||
return formArr.join("&")
|
||||
}
|
||||
|
||||
export const filterConfigs = (configs, allowed) => {
|
||||
let i, filteredConfigs = {}
|
||||
|
||||
for (i in configs) {
|
||||
if (allowed.indexOf(i) !== -1) {
|
||||
filteredConfigs[i] = configs[i]
|
||||
}
|
||||
}
|
||||
|
||||
return filteredConfigs
|
||||
}
|
||||
|
||||
// Is this really required as a helper? Perhaps. TODO: expose the system of presets.apis in docs, so we know what is supported
|
||||
export const shallowEqualKeys = (a,b, keys) => {
|
||||
return !!find(keys, (key) => {
|
||||
return eq(a[key], b[key])
|
||||
})
|
||||
}
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ function makeWindow() {
|
||||
location: {},
|
||||
history: {},
|
||||
open: () => {},
|
||||
close: () => {}
|
||||
close: () => {},
|
||||
File: function() {}
|
||||
}
|
||||
|
||||
if(typeof window === "undefined") {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import YAML from "js-yaml"
|
||||
import yamlConfig from "../../../swagger-config.yaml"
|
||||
|
||||
const CONFIGS = [ "url", "spec", "validatorUrl", "onComplete", "onFailure", "authorizations", "docExpansion",
|
||||
"apisSorter", "operationsSorter", "supportedSubmitMethods", "highlightSizeThreshold", "dom_id",
|
||||
"defaultModelRendering", "oauth2RedirectUrl", "showRequestHeaders" ]
|
||||
|
||||
const parseYamlConfig = (yaml, system) => {
|
||||
try {
|
||||
return YAML.safeLoad(yaml)
|
||||
@@ -58,16 +54,3 @@ export default function configPlugin (toolbox) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function filterConfigs (configs) {
|
||||
let i, filteredConfigs = {}
|
||||
|
||||
for (i in configs) {
|
||||
if (CONFIGS.indexOf(i) !== -1) {
|
||||
filteredConfigs[i] = configs[i]
|
||||
}
|
||||
}
|
||||
|
||||
return filteredConfigs
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
|
||||
require("core-js/fn/promise")
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
&.execute
|
||||
{
|
||||
animation: pulse 2s infinite;
|
||||
animation: swagger-ui-pulse 2s infinite;
|
||||
|
||||
color: #fff;
|
||||
border-color: #4990e2;
|
||||
@@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
|
||||
@keyframes pulse
|
||||
@keyframes swagger-ui-pulse
|
||||
{
|
||||
0%
|
||||
{
|
||||
|
||||
@@ -13,13 +13,18 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
p
|
||||
p, li, table
|
||||
{
|
||||
font-size: 14px;
|
||||
|
||||
@include text_body();
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5
|
||||
{
|
||||
@include text_body();
|
||||
}
|
||||
|
||||
code
|
||||
{
|
||||
padding: 3px 5px;
|
||||
|
||||
@@ -209,6 +209,7 @@ body
|
||||
}
|
||||
|
||||
.opblock-summary-path,
|
||||
.opblock-summary-operation-id,
|
||||
.opblock-summary-path__deprecated
|
||||
{
|
||||
font-size: 16px;
|
||||
@@ -247,6 +248,11 @@ body
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.opblock-summary-operation-id
|
||||
{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.opblock-summary-description
|
||||
{
|
||||
font-size: 13px;
|
||||
@@ -492,11 +498,18 @@ body
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
|
||||
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
hyphens: auto;
|
||||
white-space: pre-wrap;
|
||||
|
||||
|
||||
border-radius: 4px;
|
||||
background: #41444e;
|
||||
|
||||
overflow-wrap: break-word;
|
||||
@include text_code(#fff);
|
||||
span
|
||||
{
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
This module, `swagger-ui-dist`, exposes Swagger-UI's entire dist folder as a dependency-free npm module.
|
||||
# Swagger UI Dist
|
||||
[](http://badge.fury.io/js/swagger-ui-dist)
|
||||
|
||||
# API
|
||||
|
||||
This module, `swagger-ui-dist`, exposes Swagger-UI's entire dist folder as a dependency-free npm module.
|
||||
Use `swagger-ui` instead, if you'd like to have npm install dependencies for you.
|
||||
|
||||
`SwaggerUIBundle` and `SwaggerUIStandalonePreset` can be imported:
|
||||
```javascript
|
||||
import { SwaggerUIBundle, SwaggerUIStandalonePreset } from "swagger-ui-dist"
|
||||
```
|
||||
|
||||
To get an absolute path to this directory for static file serving, use the exported `getAbsoluteFSPath` method:
|
||||
|
||||
```javascript
|
||||
const swaggerUiAssetPath = require("swagger-ui-dist").getAbsoluteFSPath()
|
||||
|
||||
// then instantiate server that serves files from the swaggerUiAssetPath
|
||||
```
|
||||
|
||||
For anything else, check the [Swagger-UI](https://github.com/swagger-api/swagger-ui) repository.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* getAbsoluteFSPath
|
||||
* @return {string} When run in NodeJS env, returns the absolute path to the current directory
|
||||
* When run outside of NodeJS, will return an error message
|
||||
*/
|
||||
const getAbsoluteFSPath = function () {
|
||||
// detect whether we are running in a browser or nodejs
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
return require("path").resolve(__dirname)
|
||||
}
|
||||
throw new Error('getAbsoluteFSPath can only be called within a Nodejs environment');
|
||||
}
|
||||
|
||||
module.exports = getAbsoluteFSPath
|
||||
@@ -18,4 +18,4 @@ else
|
||||
npm pack .
|
||||
fi
|
||||
|
||||
find . -not -name .npmignore -not -name .npmrc -not -name deploy.sh -not -name package.json -not -name README.md -not -name *.tgz -delete
|
||||
find . -not -name .npmignore -not -name .npmrc -not -name deploy.sh -not -name index.js -not -name package.json -not -name README.md -not -name *.tgz -delete
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports.SwaggerUIBundle = require("./swagger-ui-bundle.js")
|
||||
module.exports.SwaggerUIStandalonePreset = require("./swagger-ui-standalone-preset.js")
|
||||
module.exports.absolutePath = require("./absolute-path.js")
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "swagger-ui-dist",
|
||||
"version": "$$VERSION",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
"(in alphabetical order)",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { render } from "enzyme"
|
||||
import Markdown from "components/providers/markdown"
|
||||
|
||||
describe("UI-3199: Sanitized Markdown causing code examples to be double escaped", function(){
|
||||
it("should single-escape quotes", function(){
|
||||
|
||||
let str = "" +
|
||||
"This is a test: \n\n" +
|
||||
" {\"abc\": \"def\"}\n"
|
||||
|
||||
let props = {
|
||||
source: str
|
||||
}
|
||||
|
||||
let el = render(<Markdown {...props}/>)
|
||||
|
||||
expect(el.find("code").first().text()).toEqual("{\"abc\": \"def\"}\n")
|
||||
expect(el.find("code").first().html()).toEqual("{"abc": "def"}\n")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
/* eslint-env mocha */
|
||||
import React from "react"
|
||||
import expect from "expect"
|
||||
import { render } from "enzyme"
|
||||
import Markdown from "components/providers/markdown"
|
||||
|
||||
describe("UI-3279: Empty Markdown inputs causing bare `undefined` in output", function(){
|
||||
it("should return no text for `null` as source input", function(){
|
||||
let props = {
|
||||
source: null
|
||||
}
|
||||
|
||||
let el = render(<Markdown {...props}/>)
|
||||
|
||||
expect(el.text()).toEqual("")
|
||||
})
|
||||
|
||||
it("should return no text for `undefined` as source input", function(){
|
||||
let props = {
|
||||
source: undefined
|
||||
}
|
||||
|
||||
let el = render(<Markdown {...props}/>)
|
||||
|
||||
expect(el.text()).toEqual("")
|
||||
})
|
||||
|
||||
it("should return no text for empty string as source input", function(){
|
||||
let props = {
|
||||
source: ""
|
||||
}
|
||||
|
||||
let el = render(<Markdown {...props}/>)
|
||||
|
||||
expect(el.text()).toEqual("")
|
||||
})
|
||||
})
|
||||
+26
-2
@@ -1,6 +1,7 @@
|
||||
import expect from "expect"
|
||||
import Im from "immutable"
|
||||
import curl from "core/curlify"
|
||||
import win from "core/window"
|
||||
|
||||
describe("curlify", function() {
|
||||
|
||||
@@ -131,12 +132,35 @@ describe("curlify", function() {
|
||||
url: "http://example.com",
|
||||
method: "POST",
|
||||
headers: { "content-type": "multipart/form-data" },
|
||||
body: "id=123&name=Sahar"
|
||||
body: [
|
||||
["id", "123"],
|
||||
["name", "Sahar"]
|
||||
]
|
||||
}
|
||||
|
||||
let curlified = curl(Im.fromJS(req))
|
||||
|
||||
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"content-type: multipart/form-data\" -F id=123 -F name=Sahar")
|
||||
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"content-type: multipart/form-data\" -F \"id=123\" -F \"name=Sahar\"")
|
||||
})
|
||||
|
||||
it("should print a curl with formData and file", function() {
|
||||
var file = new win.File()
|
||||
file.name = "file.txt"
|
||||
file.type = "text/plain"
|
||||
|
||||
var req = {
|
||||
url: "http://example.com",
|
||||
method: "POST",
|
||||
headers: { "content-type": "multipart/form-data" },
|
||||
body: [
|
||||
["id", "123"],
|
||||
["file", file]
|
||||
]
|
||||
}
|
||||
|
||||
let curlified = curl(Im.fromJS(req))
|
||||
|
||||
expect(curlified).toEqual("curl -X POST \"http://example.com\" -H \"content-type: multipart/form-data\" -F \"id=123\" -F \"file=@file.txt;type=text/plain\"")
|
||||
})
|
||||
|
||||
it("prints a curl post statement from an object", function() {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import path from "path"
|
||||
import getAbsoluteFSPath from "../../swagger-ui-dist-package/absolute-path"
|
||||
|
||||
describe("swagger-ui-dist", function(){
|
||||
describe("getAbsoluteFSPath", function(){
|
||||
it("returns absolute path", function(){
|
||||
const expectedPath = path.resolve(__dirname, "../../swagger-ui-dist-package")
|
||||
expect(getAbsoluteFSPath()).toEqual(expectedPath)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -13,7 +13,7 @@ module.exports = require('./make-webpack-config.js')({
|
||||
|
||||
entry: {
|
||||
'swagger-ui-bundle': [
|
||||
'babel-polyfill',
|
||||
'./src/polyfills',
|
||||
'./src/core/index.js'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = require('./make-webpack-config.js')({
|
||||
|
||||
entry: {
|
||||
'swagger-ui-standalone-preset': [
|
||||
'./src/polyfills',
|
||||
'./src/standalone/index.js'
|
||||
]
|
||||
},
|
||||
|
||||
+11
-12
@@ -1,9 +1,8 @@
|
||||
var path = require('path')
|
||||
var fs = require('fs')
|
||||
var node_modules = fs.readdirSync('node_modules').filter(function(x) { return x !== '.bin' })
|
||||
const path = require("path")
|
||||
const fs = require("fs")
|
||||
const nodeModules = fs.readdirSync("node_modules").filter(function(x) { return x !== ".bin" })
|
||||
|
||||
|
||||
module.exports = require('./make-webpack-config.js')({
|
||||
module.exports = require("./make-webpack-config.js")({
|
||||
_special: {
|
||||
separateStylesheets: true,
|
||||
minimize: true,
|
||||
@@ -15,9 +14,9 @@ module.exports = require('./make-webpack-config.js')({
|
||||
|
||||
entry: {
|
||||
"swagger-ui": [
|
||||
'babel-polyfill',
|
||||
'./src/style/main.scss',
|
||||
'./src/core/index.js'
|
||||
"./src/style/main.scss",
|
||||
"./src/polyfills",
|
||||
"./src/core/index.js"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -25,11 +24,11 @@ module.exports = require('./make-webpack-config.js')({
|
||||
// webpack injects some stuff into the resulting file,
|
||||
// these libs need to be pulled in to keep that working.
|
||||
var exceptionsForWebpack = ["ieee754", "base64-js"]
|
||||
if(node_modules.indexOf(request) !== -1 || exceptionsForWebpack.indexOf(request) !== -1) {
|
||||
cb(null, 'commonjs ' + request)
|
||||
return;
|
||||
if(nodeModules.indexOf(request) !== -1 || exceptionsForWebpack.indexOf(request) !== -1) {
|
||||
cb(null, "commonjs " + request)
|
||||
return
|
||||
}
|
||||
cb();
|
||||
cb()
|
||||
},
|
||||
|
||||
output: {
|
||||
|
||||
@@ -10,11 +10,13 @@ module.exports = require("./make-webpack-config")({
|
||||
devtool: "eval",
|
||||
entry: {
|
||||
'swagger-ui-bundle': [
|
||||
'babel-polyfill',
|
||||
'./src/polyfills',
|
||||
'./src/core/index.js'
|
||||
],
|
||||
'swagger-ui-standalone-preset': [
|
||||
'./src/standalone/index.js'
|
||||
'webpack/hot/dev-server',
|
||||
'./src/polyfills',
|
||||
'./src/standalone/index.js',
|
||||
]
|
||||
},
|
||||
output: {
|
||||
|
||||
Reference in New Issue
Block a user