Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f14d8067c4 | ||
|
|
c08f3c230b | ||
|
|
96f4b65dfa | ||
|
|
69fd57f17f | ||
|
|
f85fdb7835 | ||
|
|
15d43886a3 | ||
|
|
0e62d920e8 | ||
|
|
b6c3f91127 | ||
|
|
11e9bbfdbb | ||
|
|
d2c3078a79 | ||
|
|
dd11740359 | ||
|
|
8a1e447f0f | ||
|
|
ca808e9d18 | ||
|
|
f5e89dc02e | ||
|
|
2cff912261 | ||
|
|
5a5a4d016b | ||
|
|
f1f912a46f | ||
|
|
518e2ec732 | ||
|
|
862301e6df | ||
|
|
374ac9cbbb | ||
|
|
7d87c9d680 | ||
|
|
78336e99aa | ||
|
|
a7c90e2d77 | ||
|
|
87a23c7c9e | ||
|
|
d013e7a05c | ||
|
|
198f9b6874 | ||
|
|
210b20eea8 | ||
|
|
f755f80072 | ||
|
|
8137f25cc7 | ||
|
|
a8ff714eee | ||
|
|
494048e809 | ||
|
|
bcd36ff667 | ||
|
|
38ed6192c3 | ||
|
|
b9df212ccc | ||
|
|
22dc506b13 | ||
|
|
da7210d328 | ||
|
|
ca05b3e255 | ||
|
|
891c321c8a | ||
|
|
cecf0670b7 | ||
|
|
bb73dd49d8 | ||
|
|
eab557f470 | ||
|
|
ac25a5dac6 | ||
|
|
073313df6f | ||
|
|
26912b094f | ||
|
|
6f6f76caf4 | ||
|
|
bbb3035bac | ||
|
|
6841732367 | ||
|
|
1a417b3c6c | ||
|
|
aa327ed256 | ||
|
|
808f8d2827 | ||
|
|
4c40fa192b | ||
|
|
2c6bd5d988 | ||
|
|
b289d5992a | ||
|
|
5573f4d32d | ||
|
|
d6c498b5f3 | ||
|
|
a600280441 | ||
|
|
0f95724829 | ||
|
|
5ae195074f | ||
|
|
f5137da130 | ||
|
|
2bc6c5aa75 | ||
|
|
51dac3eea1 | ||
|
|
10b5c8ef8b | ||
|
|
e871871724 | ||
|
|
a6a02997e5 | ||
|
|
58e29934fd | ||
|
|
e0ecffd7c1 | ||
|
|
5a260971cc | ||
|
|
037dc71197 | ||
|
|
adf9f2d8aa | ||
|
|
06c82bb325 | ||
|
|
6cd66bb4f9 | ||
|
|
4e238ce889 | ||
|
|
1418653144 | ||
|
|
ca048f42a4 | ||
|
|
26a3ed26e8 | ||
|
|
84b408849d | ||
|
|
7790383ba6 | ||
|
|
32d7cd7204 | ||
|
|
4963c3016c | ||
|
|
0e00a68f7f | ||
|
|
754d57396a | ||
|
|
db66f56b83 | ||
|
|
8e5be08992 | ||
|
|
40d7740779 | ||
|
|
8b78d9bd13 | ||
|
|
5fc064e2ac | ||
|
|
f36a66a1b1 | ||
|
|
d5b79c70c9 | ||
|
|
35769f9b47 | ||
|
|
8e64c866e8 | ||
|
|
4b984e3c42 | ||
|
|
1794de1679 | ||
|
|
db8bd52f16 | ||
|
|
7172ed6fe9 | ||
|
|
48e0cb10b5 | ||
|
|
bedd509a4a | ||
|
|
c6279e5f25 | ||
|
|
81f74d9d51 | ||
|
|
208694e9a8 | ||
|
|
ba7a1369b8 | ||
|
|
d1d663b35f | ||
|
|
cf80839d11 | ||
|
|
de92f8deb4 | ||
|
|
99b8543562 | ||
|
|
ef60fb07a4 | ||
|
|
c45e5a3158 | ||
|
|
08b3c38b8a | ||
|
|
c7ae644c96 | ||
|
|
283722a20e | ||
|
|
89adefe392 | ||
|
|
205197d04f | ||
|
|
74008954c3 | ||
|
|
2b159372a9 | ||
|
|
5be31ac909 | ||
|
|
fce0916dca | ||
|
|
4c1a5488bb | ||
|
|
2e91ab0a2e | ||
|
|
6965a496fb | ||
|
|
e33efa1b36 | ||
|
|
3ce9baee30 | ||
|
|
1f424afe0f | ||
|
|
4da6126d10 | ||
|
|
9465d1251b | ||
|
|
f7c5515dff | ||
|
|
44ea2773cf | ||
|
|
3c98939732 | ||
|
|
f2ae188722 | ||
|
|
5e571fac51 | ||
|
|
8e60343417 | ||
|
|
e2b1757f8f | ||
|
|
2535758adf | ||
|
|
2a6ecb2d38 | ||
|
|
6a36b58977 | ||
|
|
7169ea32c9 |
@@ -0,0 +1,3 @@
|
||||
When reporting an issue, please provide the following details:
|
||||
- swagger-ui version
|
||||
- a swagger file reproducing the issue
|
||||
+34
-16
@@ -7,26 +7,44 @@ branches:
|
||||
only:
|
||||
- master
|
||||
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
before_deploy: "npm run build-core"
|
||||
before_deploy:
|
||||
- npm run build
|
||||
env:
|
||||
- DOCKER_IMAGE_NAME=swaggerapi/swagger-ui
|
||||
deploy:
|
||||
provider: npm
|
||||
email: apiteam@swagger.io
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: "IJkLaACa+rfERf1O5nwlqOyuo9sbul3FBhBt4Un9P+DvEet3AoDPV9NQVLd8SkmQYKGbGQWF4BIdjrO5nqFD6Te+JTeUX5Uo/DFS/fu9qw1xv0dQpvbJFuoYnnFlbzGTEs4CFa8lbu3ZromFHQGOQxRobjsG1Kf0dWFSSzmND3g="
|
||||
on:
|
||||
tags: true
|
||||
repo: swagger-api/swagger-ui
|
||||
node: '6.9'
|
||||
- provider: npm
|
||||
email: apiteam@swagger.io
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: "IJkLaACa+rfERf1O5nwlqOyuo9sbul3FBhBt4Un9P+DvEet3AoDPV9NQVLd8SkmQYKGbGQWF4BIdjrO5nqFD6Te+JTeUX5Uo/DFS/fu9qw1xv0dQpvbJFuoYnnFlbzGTEs4CFa8lbu3ZromFHQGOQxRobjsG1Kf0dWFSSzmND3g="
|
||||
on:
|
||||
tags: true
|
||||
repo: swagger-api/swagger-ui
|
||||
node: '6.9'
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: swagger-ui-dist-package/deploy.sh
|
||||
on:
|
||||
tags: true
|
||||
repo: swagger-api/swagger-ui
|
||||
node: '6.9'
|
||||
after_success:
|
||||
- if [ $DOCKER_HUB_USERNAME ]; then
|
||||
- if [ $DOCKER_HUB_USERNAME ]; then
|
||||
docker login --email=$DOCKER_HUB_EMAIL --username=$DOCKER_HUB_USERNAME --password=$DOCKER_HUB_PASSWORD;
|
||||
docker build -t $DOCKER_IMAGE_NAME .;
|
||||
if [ "$TRAVIS_TAG" != "master" && -z "$TRAVIS_TAG"]; then
|
||||
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:$TRAVIS_TAG;
|
||||
fi;
|
||||
|
||||
docker push $DOCKER_IMAGE_NAME;
|
||||
if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
DOCKER_IMAGE_TAG=$TRAVIS_TAG;
|
||||
else
|
||||
DOCKER_IMAGE_TAG=unstable;
|
||||
fi;
|
||||
docker build -t $DOCKER_IMAGE_NAME .;
|
||||
if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
|
||||
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
|
||||
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:latest;
|
||||
docker push $DOCKER_IMAGE_NAME:latest;
|
||||
else
|
||||
docker tag $DOCKER_IMAGE_NAME $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
|
||||
docker push $DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
+14
-1
@@ -2,6 +2,18 @@ FROM alpine:3.4
|
||||
|
||||
MAINTAINER fehguy
|
||||
|
||||
ENV VERSION "v2.2.10"
|
||||
ENV FOLDER "swagger-ui-2.2.10"
|
||||
ENV API_URL "http://petstore.swagger.io/v2/swagger.json"
|
||||
ENV API_KEY "**None**"
|
||||
ENV OAUTH_CLIENT_ID "**None**"
|
||||
ENV OAUTH_CLIENT_SECRET "**None**"
|
||||
ENV OAUTH_REALM "**None**"
|
||||
ENV OAUTH_APP_NAME "**None**"
|
||||
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
|
||||
ENV SWAGGER_JSON "/app/swagger.json"
|
||||
ENV PORT 80
|
||||
|
||||
RUN apk add --update nginx
|
||||
RUN mkdir -p /run/nginx
|
||||
|
||||
@@ -9,7 +21,8 @@ COPY nginx.conf /etc/nginx/
|
||||
|
||||
# copy swagger files to the `/js` folder
|
||||
ADD ./dist/* /usr/share/nginx/html/
|
||||
ADD ./docker-run.sh /usr/share/nginx/
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD exec nginx -g 'daemon off;'
|
||||
CMD ["sh", "/usr/share/nginx/docker-run.sh"]
|
||||
|
||||
@@ -15,7 +15,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.5 | 2017-03-19 | 2.0 | [tag v3.0.5](https://github.com/swagger-api/swagger-ui/tree/v3.0.5) |
|
||||
3.0.8 | 2017-03-19 | 2.0 | [tag v3.0.8](https://github.com/swagger-api/swagger-ui/tree/v3.0.8) |
|
||||
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) |
|
||||
@@ -58,7 +58,7 @@ To help with the migration, here are the currently known issues with 3.X. This l
|
||||
- Relative path support for external files is not implemented.
|
||||
|
||||
### SwaggerUIBundle
|
||||
To use swagger-ui 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 and call load() on it as below:
|
||||
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:
|
||||
|
||||
```javascript
|
||||
const ui = SwaggerUIBundle({
|
||||
@@ -75,6 +75,8 @@ To use swagger-ui you should take a look at the [source of swagger-ui html page]
|
||||
})
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Parameter Name | Description
|
||||
@@ -84,6 +86,7 @@ spec | A JSON object describing the OpenAPI Specification. When used, the `url`
|
||||
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
|
||||
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -90,4 +90,4 @@ window.onload = function() {
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Vendored
+7
-37
@@ -8,11 +8,13 @@
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var isValid, qp;
|
||||
var isValid, qp, arr;
|
||||
|
||||
qp = (window.location.hash || location.search).substring(1);
|
||||
|
||||
qp = qp ? JSON.parse('{"' + qp.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
|
||||
arr = qp.split("&")
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value)
|
||||
}
|
||||
@@ -33,51 +35,19 @@
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
createForm(oauth2.auth, qp).submit();
|
||||
oauth2.callback(oauth2.auth);
|
||||
} else {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: "Authorization failed: no accessCode came from the server"
|
||||
message: "Authorization failed: no accessCode received from the server"
|
||||
});
|
||||
window.close();
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid});
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
function createForm(auth, qp) {
|
||||
var form = document.createElement("form");
|
||||
var schema = auth.schema;
|
||||
var action = schema.get("tokenUrl");
|
||||
var name, input;
|
||||
|
||||
var fields = {
|
||||
code: qp.code,
|
||||
"redirect_uri": location.protocol + "//" + location.host + location.pathname,
|
||||
"grant_type": "authorization_code",
|
||||
"client_secret": auth.clientSecret,
|
||||
"client_id": auth.clientId
|
||||
}
|
||||
|
||||
for ( name in fields ) {
|
||||
input = document.createElement("input");
|
||||
input.name = name;
|
||||
input.value = fields[name];
|
||||
input.type = "hidden";
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
|
||||
form.method = "POST";
|
||||
form.action = action;
|
||||
|
||||
document.body.appendChild(form);
|
||||
|
||||
return form;
|
||||
window.close();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
Vendored
+42
-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;;;;;;;;;;;;;;;;;;;;;;;;;;AA0dA;;;;;;AAoIA;AAk7FA;AAmtCA;;;;;AA0uIA;AA66IA;AA27FA;AAuwGA;AAilFA;AAikFA;AAs9CA;AA8jDA;AA2qCA;AA4tEA;AAgkIA;;;;;;;;;;;;;;AAw4GA;AAyoIA;AAiuJA;AA8kHA;AAonGA;AAukEA;AA02DA;AAyxDA;AAw6BA;;;;;;AA8vEA;AA+zFA;;;;;AA23CA;AA2qFA;AAq2CA;AA0kCA;AAs/CA;AA0wEA;AA49FA;;;;;;;;;AA20BA;AA2zIA;AAi4DA;AA6tDA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;AAu/FA;AA6+FA;;;;;;;;;;;;;;;;;;;;;;;;;;AAmTA;;;;;;AAoIA;AAi7FA;AAmtCA;AAi0IA;AA2pJA;AA+uFA;AA2rGA;AAgiFA;AA0rFA;AAk9CA;AA2hDA;AA4rCA;AAi6EA;;;;;AA2gCA;AA02JA;;;;;;;;;;;;;;AAuyEA;AA4mIA;AAquJA;AAwsHA;AA2mGA;AAiiEA;AAq4DA;AA+2DA;AAqlBA;;;;;;AAilFA;AAs1FA;;;;;AAy3CA;AA2qFA;AAw2CA;AAwkCA;AAs/CA;AA4kFA;AAy1FA;;;;;;;;;AAm5CA;AA2zIA;AAk4DA;AAolDA","sourceRoot":""}
|
||||
Vendored
+3
-3
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;;;;;AA2SA;AAyiGA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA4QA;AAitGA","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;;;;;;AAuwCA;AAoyHA;AA2wHA;AA07FA;AA+nCA;AAohCA;AAghCA;AAk4BA","sourceRoot":""}
|
||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAwxCA;AAoyHA;AAuxHA;AAy4FA;AA2sCA;AAmgCA;AA0iCA;AA+3BA","sourceRoot":""}
|
||||
@@ -0,0 +1,48 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
INDEX_FILE=/usr/share/nginx/html/index.html
|
||||
|
||||
replace_in_index () {
|
||||
if [ "$1" != "**None**" ]; then
|
||||
sed -i "s|/\*||g" $INDEX_FILE
|
||||
sed -i "s|\*/||g" $INDEX_FILE
|
||||
sed -i "s|$1|$2|g" $INDEX_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
replace_or_delete_in_index () {
|
||||
if [ -z "$2" ]; then
|
||||
sed -i "/$1/d" $INDEX_FILE
|
||||
else
|
||||
replace_in_index $1 $2
|
||||
fi
|
||||
}
|
||||
|
||||
replace_in_index myApiKeyXXXX123456789 $API_KEY
|
||||
replace_or_delete_in_index your-client-id $OAUTH_CLIENT_ID
|
||||
replace_or_delete_in_index your-client-secret-if-required $OAUTH_CLIENT_SECRET
|
||||
replace_or_delete_in_index your-realms $OAUTH_REALM
|
||||
replace_or_delete_in_index your-app-name $OAUTH_APP_NAME
|
||||
if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
|
||||
replace_in_index "additionalQueryStringParams: {}" "additionalQueryStringParams: {$OAUTH_ADDITIONAL_PARAMS}"
|
||||
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
|
||||
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
|
||||
fi
|
||||
|
||||
if [[ -n "$VALIDATOR_URL" ]]; then
|
||||
sed -i "s|.*validatorUrl:.*$||g" $INDEX_FILE
|
||||
TMP_VU="$VALIDATOR_URL"
|
||||
[[ "$VALIDATOR_URL" != "null" && "$VALIDATOR_URL" != "undefined" ]] && TMP_VU="\"${VALIDATOR_URL}\""
|
||||
sed -i "s|\(url: .*,\)|\1\n validatorUrl: ${TMP_VU},|g" $INDEX_FILE
|
||||
unset TMP_VU
|
||||
fi
|
||||
|
||||
exec nginx -g 'daemon off;'
|
||||
@@ -4,9 +4,13 @@ var webpack = require('webpack')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
var deepExtend = require('deep-extend')
|
||||
var autoprefixer = require('autoprefixer')
|
||||
const {gitDescribeSync} = require('git-describe');
|
||||
|
||||
var loadersByExtension = require('./build-tools/loadersByExtension')
|
||||
|
||||
var pkg = require('./package.json')
|
||||
const gitInfo = gitDescribeSync(__dirname)
|
||||
|
||||
module.exports = function(options) {
|
||||
|
||||
// Special options, that have logic in this file
|
||||
@@ -60,7 +64,13 @@ module.exports = function(options) {
|
||||
'process.env': {
|
||||
NODE_ENV: specialOptions.minimize ? JSON.stringify('production') : null,
|
||||
WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets)
|
||||
|
||||
},
|
||||
'buildInfo': JSON.stringify({
|
||||
PACKAGE_VERSION: (pkg.version),
|
||||
GIT_COMMIT: gitInfo.hash,
|
||||
GIT_DIRTY: gitInfo.dirty
|
||||
})
|
||||
}))
|
||||
|
||||
var cssLoader = 'css-loader!postcss-loader'
|
||||
|
||||
+7
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.0.5",
|
||||
"version": "3.0.8",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -36,10 +36,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"base64-js": "^1.2.0",
|
||||
"brace": "0.7.0",
|
||||
"deep-extend": "0.4.1",
|
||||
"expect": "1.20.2",
|
||||
"getbase": "^2.8.2",
|
||||
"ieee754": "^1.1.8",
|
||||
"immutable": "^3.x.x",
|
||||
"js-yaml": "^3.5.5",
|
||||
"less": "2.7.1",
|
||||
@@ -67,7 +69,8 @@
|
||||
"reselect": "2.5.3",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.0.5",
|
||||
"swagger-client": "^3.0.8",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
"xml": "1.0.1",
|
||||
@@ -92,6 +95,7 @@
|
||||
"eslint-plugin-react": "^6.10.3",
|
||||
"extract-text-webpack-plugin": "0.8.2",
|
||||
"file-loader": "0.8.4",
|
||||
"git-describe": "^4.0.1",
|
||||
"html-webpack-plugin": "^2.28.0",
|
||||
"imports-loader": "0.6.5",
|
||||
"json-loader": "0.5.3",
|
||||
@@ -111,6 +115,7 @@
|
||||
"postcss-loader": "0.7.0",
|
||||
"raw-loader": "0.5.1",
|
||||
"react-hot-loader": "^1.3.1",
|
||||
"react-test-renderer": "^15.5.4",
|
||||
"rimraf": "^2.6.0",
|
||||
"sass-loader": "^6.0.2",
|
||||
"standard": "^8.6.0",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
name: swagger-ui
|
||||
version: master
|
||||
summary: The World's Most Popular API Framework
|
||||
description: |
|
||||
Swagger UI is part of the Swagger project. The Swagger project allows you to
|
||||
produce, visualize and consume your OWN RESTful services. No proxy or 3rd
|
||||
party services required. Do it your own way.
|
||||
|
||||
Swagger UI is a dependency-free collection of HTML, Javascript, and CSS
|
||||
assets that dynamically generate beautiful documentation and sandbox from a
|
||||
Swagger-compliant API. Because Swagger UI has no dependencies, you can host
|
||||
it in any server environment, or on your local machine.
|
||||
|
||||
grade: devel
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
swagger-ui:
|
||||
command: sh -c \"cd $SNAP/lib/node_modules/swagger-ui/dist && http-server -a localhost -p 8080\"
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
parts:
|
||||
swagger-ui:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
npm-run: [build]
|
||||
node-packages: [handlebars, http-server]
|
||||
@@ -64,11 +64,10 @@ export default class ApiKeyAuth extends React.Component {
|
||||
</Row>
|
||||
<Row>
|
||||
<label>Value:</label>
|
||||
<Col>
|
||||
{
|
||||
value || <Input type="text" onChange={ this.onChange }/>
|
||||
}
|
||||
</Col>
|
||||
{
|
||||
value ? <code> ****** </code>
|
||||
: <Col><Input type="text" onChange={ this.onChange }/></Col>
|
||||
}
|
||||
</Row>
|
||||
{
|
||||
errors.valueSeq().map( (error, key) => {
|
||||
|
||||
@@ -16,6 +16,10 @@ export default class AuthorizeOperationBtn extends React.Component {
|
||||
|
||||
let isAuthorized = authSelectors.isAuthorized(security)
|
||||
|
||||
if(isAuthorized === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
|
||||
<svg width="20" height="20">
|
||||
|
||||
@@ -63,19 +63,23 @@ export default class BasicAuth extends React.Component {
|
||||
source={ schema.get("description") } />
|
||||
</Row>
|
||||
<Row>
|
||||
<Col tablet={2} desktop={2}>username:</Col>
|
||||
<Col tablet={10} desktop={10}>
|
||||
<label>Username:</label>
|
||||
{
|
||||
username ? <code> { username } </code>
|
||||
: <Col><Input type="text" required="required" name="username" onChange={ this.onChange }/></Col>
|
||||
}
|
||||
</Row>
|
||||
<Row>
|
||||
<label>Password:</label>
|
||||
{
|
||||
username || <Input type="text" required="required" name="username" onChange={ this.onChange }/>
|
||||
username ? <code> ****** </code>
|
||||
: <Col><Input required="required"
|
||||
autoComplete="new-password"
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={ this.onChange }/></Col>
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
!username && <Row>
|
||||
<Col tablet={2} desktop={2}>password:</Col>
|
||||
<Col tablet={10} desktop={10}><Input required="required" autoComplete="new-password" name="password" type="password" onChange={ this.onChange }/></Col>
|
||||
</Row>
|
||||
}
|
||||
{
|
||||
errors.valueSeq().map( (error, key) => {
|
||||
return <AuthError error={ error }
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class Oauth2 extends React.Component {
|
||||
let username = auth && auth.get("username") || ""
|
||||
let clientId = auth && auth.get("clientId") || ""
|
||||
let clientSecret = auth && auth.get("clientSecret") || ""
|
||||
let passwordType = auth && auth.get("passwordType") || "none"
|
||||
let passwordType = auth && auth.get("passwordType") || "basic"
|
||||
|
||||
this.state = {
|
||||
name: name,
|
||||
@@ -108,66 +108,69 @@ export default class Oauth2 extends React.Component {
|
||||
<p className="flow">Flow: <code>{ schema.get("flow") }</code></p>
|
||||
|
||||
{
|
||||
flow === PASSWORD && ( !isAuthorized || isAuthorized && this.state.username) && <Row>
|
||||
<Col tablet={2} desktop={2}>username:</Col>
|
||||
<Col tablet={10} desktop={10}>
|
||||
flow !== PASSWORD ? null
|
||||
: <Row>
|
||||
<Row>
|
||||
<label htmlFor="oauth_username">username:</label>
|
||||
{
|
||||
isAuthorized ? <code> { this.state.username } </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="oauth_username" type="text" data-name="username" onChange={ this.onInputChange }/>
|
||||
</Col>
|
||||
}
|
||||
</Row>
|
||||
{
|
||||
isAuthorized ? <span>{ this.state.username }</span>
|
||||
: <input type="text" data-name="username" onChange={ this.onInputChange }/>
|
||||
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<label htmlFor="oauth_password">password:</label>
|
||||
{
|
||||
isAuthorized ? <code> ****** </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="oauth_password" type="password" data-name="password" onChange={ this.onInputChange }/>
|
||||
</Col>
|
||||
}
|
||||
</Row>
|
||||
<Row>
|
||||
<label htmlFor="password_type">type:</label>
|
||||
{
|
||||
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="query">Query parameters</option>
|
||||
</select>
|
||||
</Col>
|
||||
}
|
||||
</Row>
|
||||
</Row>
|
||||
}
|
||||
|
||||
{
|
||||
flow === PASSWORD && !isAuthorized && <Row>
|
||||
<Col tablet={2} desktop={2}>password:</Col>
|
||||
<Col tablet={10} desktop={10}>
|
||||
<input type="password" data-name="password" onChange={ this.onInputChange }/>
|
||||
</Col>
|
||||
</Row>
|
||||
}
|
||||
|
||||
{
|
||||
flow === PASSWORD && <Row>
|
||||
<Col tablet={2} desktop={2}>type:</Col>
|
||||
<Col tablet={10} desktop={10}>
|
||||
{
|
||||
isAuthorized ? <span>{ this.state.passwordType }</span>
|
||||
: <select data-name="passwordType" onChange={ this.onInputChange }>
|
||||
<option value="none">None or other</option>
|
||||
<option value="basic">Basic auth</option>
|
||||
<option value="request">Request body</option>
|
||||
</select>
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
}
|
||||
|
||||
{
|
||||
( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) &&
|
||||
( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) &&
|
||||
( !isAuthorized || isAuthorized && this.state.clientId) && <Row>
|
||||
<label htmlFor="client_id">client_id:</label>
|
||||
<Col tablet={10} desktop={10}>
|
||||
{
|
||||
isAuthorized ? <span>{ this.state.clientId }</span>
|
||||
: <input id="client_id" type="text" required={ flow === PASSWORD } data-name="clientId"
|
||||
{
|
||||
isAuthorized ? <code> ****** </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="client_id" type="text" required={ flow === PASSWORD } data-name="clientId"
|
||||
onChange={ this.onInputChange }/>
|
||||
}
|
||||
</Col>
|
||||
</Col>
|
||||
}
|
||||
</Row>
|
||||
}
|
||||
|
||||
{
|
||||
( flow === APPLICATION || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && <Row>
|
||||
( flow === APPLICATION || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) && <Row>
|
||||
<label htmlFor="client_secret">client_secret:</label>
|
||||
<Col tablet={10} desktop={10}>
|
||||
{
|
||||
isAuthorized ? <span>{ this.state.clientSecret }</span>
|
||||
: <input id="client_secret" type="text" data-name="clientSecret"
|
||||
{
|
||||
isAuthorized ? <code> ****** </code>
|
||||
: <Col tablet={10} desktop={10}>
|
||||
<input id="client_secret" type="text" data-name="clientSecret"
|
||||
onChange={ this.onInputChange }/>
|
||||
}
|
||||
</Col>
|
||||
</Col>
|
||||
}
|
||||
|
||||
</Row>
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export class Container extends React.Component {
|
||||
if(fullscreen)
|
||||
return <section {...rest}/>
|
||||
|
||||
let containerClass = "container" + (full ? "-full" : "")
|
||||
let containerClass = "swagger-container" + (full ? "-full" : "")
|
||||
return (
|
||||
<section {...rest} className={xclass(rest.className, containerClass)}/>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, { PropTypes } from "react"
|
||||
|
||||
export default class BaseLayout extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
errSelectors: PropTypes.object.isRequired,
|
||||
errActions: PropTypes.object.isRequired,
|
||||
specActions: PropTypes.object.isRequired,
|
||||
specSelectors: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
let { specSelectors, specActions, getComponent } = this.props
|
||||
|
||||
let info = specSelectors.info()
|
||||
let url = specSelectors.url()
|
||||
let basePath = specSelectors.basePath()
|
||||
let host = specSelectors.host()
|
||||
let securityDefinitions = specSelectors.securityDefinitions()
|
||||
let externalDocs = specSelectors.externalDocs()
|
||||
let schemes = specSelectors.schemes()
|
||||
|
||||
let Info = getComponent("info")
|
||||
let Operations = getComponent("operations", true)
|
||||
let Models = getComponent("models", true)
|
||||
let AuthorizeBtn = getComponent("authorizeBtn", true)
|
||||
let Row = getComponent("Row")
|
||||
let Col = getComponent("Col")
|
||||
let Errors = getComponent("errors", true)
|
||||
const Schemes = getComponent("schemes")
|
||||
|
||||
const isSpecEmpty = !specSelectors.specStr()
|
||||
|
||||
if(isSpecEmpty) {
|
||||
return <h4>No spec provided.</h4>
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<div className='swagger-ui'>
|
||||
<div>
|
||||
<Errors/>
|
||||
<Row className="information-container">
|
||||
<Col mobile={12}>
|
||||
{ info.count() ? (
|
||||
<Info info={ info } url={ url } host={ host } basePath={ basePath } externalDocs={externalDocs} getComponent={getComponent}/>
|
||||
) : null }
|
||||
</Col>
|
||||
</Row>
|
||||
{ schemes && schemes.size || securityDefinitions ? (
|
||||
<div className="scheme-container">
|
||||
<Col className="schemes wrapper" mobile={12}>
|
||||
{ schemes && schemes.size ? (
|
||||
<Schemes schemes={ schemes } specActions={ specActions } />
|
||||
) : null }
|
||||
{ securityDefinitions ? (
|
||||
<AuthorizeBtn />
|
||||
) : null }
|
||||
</Col>
|
||||
</div>
|
||||
) : null }
|
||||
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
<Operations/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
<Models/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -55,9 +55,10 @@ export default class ParamBody extends Component {
|
||||
let isXml = /xml/i.test(consumesValue)
|
||||
let paramValue = isXml ? parameter.get("value_xml") : parameter.get("value")
|
||||
|
||||
if ( paramValue ) {
|
||||
this.setState({ value: paramValue })
|
||||
this.onChange(paramValue, {isXml: isXml, isEditBox: isExecute})
|
||||
if ( paramValue !== undefined ) {
|
||||
let val = !paramValue && !isXml ? "{}" : paramValue
|
||||
this.setState({ value: val })
|
||||
this.onChange(val, {isXml: isXml, isEditBox: isExecute})
|
||||
} else {
|
||||
if (isXml) {
|
||||
this.onChange(this.sample("xml"), {isXml: isXml, isEditBox: isExecute})
|
||||
|
||||
+7
-1
@@ -6,6 +6,12 @@ import * as AllPlugins from "core/plugins/all"
|
||||
import { filterConfigs } from "plugins/configs"
|
||||
import { parseSeach } from "core/utils"
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION } = buildInfo
|
||||
|
||||
window.versions = window.versions || {}
|
||||
window.versions.swaggerUi = `${PACKAGE_VERSION}/${GIT_COMMIT || "unknown"}${GIT_DIRTY ? "-dirty" : ""}`
|
||||
|
||||
module.exports = function SwaggerUI(opts) {
|
||||
|
||||
const defaults = {
|
||||
@@ -13,7 +19,7 @@ module.exports = function SwaggerUI(opts) {
|
||||
dom_id: null,
|
||||
spec: {},
|
||||
url: "",
|
||||
layout: "Layout",
|
||||
layout: "BaseLayout",
|
||||
validatorUrl: "https://online.swagger.io/validator",
|
||||
configs: {
|
||||
},
|
||||
|
||||
@@ -150,9 +150,9 @@ export class JsonSchema_array extends Component {
|
||||
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
|
||||
value.map( (item,i) => {
|
||||
let schema = Object.assign({}, itemSchema)
|
||||
let err = errors.filter((err) => err.index === i)
|
||||
if ( err.length ) {
|
||||
schema.errors = [ err[0].error + i ]
|
||||
if ( errors.length ) {
|
||||
let err = errors.filter((err) => err.index === i)
|
||||
if (err.length) schema.errors = [ err[0].error + i ]
|
||||
}
|
||||
return (
|
||||
<div key={i} className="json-schema-form-item">
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import win from "core/window"
|
||||
import { btoa } from "core/utils"
|
||||
|
||||
export default function authorize ( auth, authActions, errActions, configs ) {
|
||||
let { schema, scopes, name, clientId } = auth
|
||||
|
||||
let redirectUrl = configs.oauth2RedirectUrl
|
||||
let scopeSeparator = " "
|
||||
let state = name
|
||||
let state = btoa(new Date())
|
||||
let flow = schema.get("flow")
|
||||
let url
|
||||
|
||||
@@ -15,7 +16,7 @@ export default function authorize ( auth, authActions, errActions, configs ) {
|
||||
}
|
||||
|
||||
if (flow === "application") {
|
||||
authActions.authorizeOauth2Application(auth)
|
||||
authActions.authorizeApplication(auth)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,7 +45,7 @@ export default function authorize ( auth, authActions, errActions, configs ) {
|
||||
win.swaggerUIRedirectOauth2 = {
|
||||
auth: auth,
|
||||
state: state,
|
||||
callback: authActions.preAuthorizeOauth2,
|
||||
callback: flow === "implicit" ? authActions.preAuthorizeImplicit : authActions.authorizeAccessCode,
|
||||
errCb: errActions.newAuthErr
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import win from "core/window"
|
||||
import { btoa } from "core/utils"
|
||||
import { btoa, buildFormData } from "core/utils"
|
||||
|
||||
export const SHOW_AUTH_POPUP = "show_popup"
|
||||
export const AUTHORIZE = "authorize"
|
||||
@@ -31,7 +31,7 @@ export function logout(payload) {
|
||||
}
|
||||
}
|
||||
|
||||
export const preAuthorizeOauth2 = (payload) => ( { authActions, errActions } ) => {
|
||||
export const preAuthorizeImplicit = (payload) => ( { authActions, errActions } ) => {
|
||||
let { auth , token, isValid } = payload
|
||||
let { schema, name } = auth
|
||||
let flow = schema.get("flow")
|
||||
@@ -68,29 +68,72 @@ export function authorizeOauth2(payload) {
|
||||
}
|
||||
}
|
||||
|
||||
export const authorizePassword = ( auth ) => ( { fn, authActions, errActions } ) => {
|
||||
export const authorizePassword = ( auth ) => ( { authActions } ) => {
|
||||
let { schema, name, username, password, passwordType, clientId, clientSecret } = auth
|
||||
let req = {
|
||||
url: schema.get("tokenUrl"),
|
||||
method: "post",
|
||||
headers: {
|
||||
"content-type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
query: {
|
||||
grant_type: "password",
|
||||
username,
|
||||
password,
|
||||
scopes: encodeURIComponent(auth.scopes.join(scopeSeparator))
|
||||
let form = {
|
||||
grant_type: "password",
|
||||
scopes: encodeURIComponent(auth.scopes.join(scopeSeparator))
|
||||
}
|
||||
let query = {}
|
||||
let headers = {}
|
||||
|
||||
if ( passwordType === "basic") {
|
||||
headers.Authorization = "Basic " + btoa(username + ":" + password)
|
||||
} else {
|
||||
Object.assign(form, {username}, {password})
|
||||
if ( passwordType === "query") {
|
||||
if ( clientId ) { query.client_id = clientId }
|
||||
if ( clientSecret ) { query.client_secret = clientSecret }
|
||||
} else {
|
||||
Object.assign(form, {client_id: clientId}, {client_secret: clientSecret})
|
||||
}
|
||||
}
|
||||
|
||||
if ( passwordType === "basic") {
|
||||
req.headers.authorization = "Basic " + btoa(clientId + ":" + clientSecret)
|
||||
} else if ( passwordType === "request") {
|
||||
req.query = Object.assign(req.query, { client_id: clientId, client_secret: clientSecret })
|
||||
return authActions.authorizeRequest({ body: buildFormData(form), url: schema.get("tokenUrl"), name, headers, query, auth})
|
||||
}
|
||||
|
||||
export const authorizeApplication = ( auth ) => ( { authActions } ) => {
|
||||
let { schema, scopes, name, clientId, clientSecret } = auth
|
||||
let form = {
|
||||
grant_type: "client_credentials",
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
scope: scopes.join(scopeSeparator)
|
||||
}
|
||||
return fn.fetch(req)
|
||||
.then(( response ) => {
|
||||
|
||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth })
|
||||
}
|
||||
|
||||
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 authorizeRequest = ( data ) => ( { fn, authActions, errActions } ) => {
|
||||
let { body, query={}, headers={}, name, url, auth } = data
|
||||
|
||||
let _headers = Object.assign({
|
||||
"Accept":"application/json, text/plain, */*",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}, headers)
|
||||
|
||||
fn.fetch({
|
||||
url: url,
|
||||
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 || "" )
|
||||
@@ -115,39 +158,14 @@ export const authorizePassword = ( auth ) => ( { fn, authActions, errActions } )
|
||||
return
|
||||
}
|
||||
|
||||
authActions.authorizeOauth2({ auth, token })
|
||||
authActions.authorizeOauth2({ auth, token})
|
||||
})
|
||||
.catch(err => { errActions.newAuthErr( err ) })
|
||||
}
|
||||
|
||||
export const authorizeOauth2Application = ( auth ) => ( { fn, authActions, errActions } ) => {
|
||||
let { schema, scopes, name, clientId, clientSecret } = auth
|
||||
|
||||
fn.fetch(schema.get("tokenUrl"), {
|
||||
method: "post", headers: {
|
||||
"Accept":"application/json, text/plain, */*",
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: "grant_type=client_credentials" +
|
||||
"&client_id=" + encodeURIComponent(clientId) +
|
||||
"&client_secret=" + encodeURIComponent(clientSecret) +
|
||||
"&scope=" + encodeURIComponent(scopes.join(scopeSeparator))
|
||||
})
|
||||
.then(function (response) {
|
||||
if ( !response.ok ) {
|
||||
.catch(e => {
|
||||
let err = new Error(e)
|
||||
errActions.newAuthErr( {
|
||||
authId: name,
|
||||
level: "error",
|
||||
source: "auth",
|
||||
message: response.statusText
|
||||
} )
|
||||
return
|
||||
} else {
|
||||
response.json()
|
||||
.then(function (json){
|
||||
authActions.authorizeOauth2({ auth, token: json})
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => { errActions.newAuthErr( err ) })
|
||||
message: err.message
|
||||
} ) })
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ export const authorized = createSelector(
|
||||
export const isAuthorized = ( state, securities ) =>( { authSelectors } ) => {
|
||||
let authorized = authSelectors.authorized()
|
||||
|
||||
if(!List.isList(securities)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return !!securities.toJS().filter( ( security ) => {
|
||||
let isAuthorized = true
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
let obj = {}
|
||||
for (var name in props) {
|
||||
if ( !props[name].readOnly || includeReadOnly ) {
|
||||
obj[name] = sampleFromSchema(props[name])
|
||||
obj[name] = sampleFromSchema(props[name], { includeReadOnly: includeReadOnly })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
obj.additionalProp1 = {}
|
||||
} else if ( additionalProperties ) {
|
||||
let additionalProps = objectify(additionalProperties)
|
||||
let additionalPropVal = sampleFromSchema(additionalProps)
|
||||
let additionalPropVal = sampleFromSchema(additionalProps, { includeReadOnly: includeReadOnly })
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
obj["additionalProp" + i] = additionalPropVal
|
||||
@@ -65,7 +65,7 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
}
|
||||
|
||||
if(type === "array") {
|
||||
return [ sampleFromSchema(items) ]
|
||||
return [ sampleFromSchema(items, { includeReadOnly: includeReadOnly }) ]
|
||||
}
|
||||
|
||||
if(schema["enum"]) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import YAML from "js-yaml"
|
||||
import parseUrl from "url-parse"
|
||||
import serializeError from "serialize-error"
|
||||
|
||||
// Actions conform to FSA (flux-standard-actions)
|
||||
@@ -186,7 +187,11 @@ export const logRequest = (req) => {
|
||||
// (For debugging) and ease of testing
|
||||
export const executeRequest = (req) => ({fn, specActions, specSelectors}) => {
|
||||
let { pathName, method } = req
|
||||
let parsedRequest = Object.assign({ contextUrl: specSelectors.url() }, req)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -97,7 +97,11 @@ export default {
|
||||
},
|
||||
|
||||
[UPDATE_OPERATION_VALUE]: (state, { payload: { path, value, key } }) => {
|
||||
return state.setIn(["resolved", "paths", ...path, key], fromJS(value))
|
||||
let operationPath = ["resolved", "paths", ...path]
|
||||
if(!state.getIn(operationPath)) {
|
||||
return state
|
||||
}
|
||||
return state.setIn([...operationPath, key], fromJS(value))
|
||||
},
|
||||
|
||||
[CLEAR_RESPONSE]: (state, { payload: { path, method } } ) =>{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createSelector } from "reselect"
|
||||
import { sorters } from "core/utils"
|
||||
import { fromJS, Set, Map, List } from "immutable"
|
||||
|
||||
const DEFAULT_TAG = "default"
|
||||
@@ -198,13 +199,16 @@ export const operationsWithTags = createSelector(
|
||||
}
|
||||
)
|
||||
|
||||
export const taggedOperations = createSelector(
|
||||
state,
|
||||
operationsWithTags,
|
||||
(state, tagMap) => {
|
||||
return tagMap.map((ops, tag) => Map({tagDetails: tagDetails(state, tag), operations: ops}))
|
||||
}
|
||||
)
|
||||
export const taggedOperations = ( state ) =>( { getConfigs } ) => {
|
||||
let { operationsSorter }= getConfigs()
|
||||
|
||||
return operationsWithTags(state).map((ops, tag) => {
|
||||
let sortFn = typeof operationsSorter === "function" ? operationsSorter
|
||||
: sorters.operationsSorter[operationsSorter]
|
||||
let operations = !sortFn ? ops : ops.sort(sortFn)
|
||||
|
||||
return Map({tagDetails: tagDetails(state, tag), operations: operations})})
|
||||
}
|
||||
|
||||
export const responses = createSelector(
|
||||
state,
|
||||
@@ -291,7 +295,11 @@ export function operationConsumes(state, pathMethod) {
|
||||
}
|
||||
|
||||
export const operationScheme = ( state, path, method ) => {
|
||||
return state.getIn(["scheme", path, method]) || state.getIn(["scheme", "_defaultScheme"]) || "http"
|
||||
let url = state.get("url")
|
||||
let matchResult = url.match(/^([a-z][a-z0-9+\-.]*):/)
|
||||
let urlScheme = Array.isArray(matchResult) ? matchResult[1] : null
|
||||
|
||||
return state.getIn(["scheme", path, method]) || state.getIn(["scheme", "_defaultScheme"]) || urlScheme || ""
|
||||
}
|
||||
|
||||
export const canExecuteScheme = ( state, path, method ) => {
|
||||
|
||||
@@ -74,7 +74,7 @@ const createClass = component => React.createClass({
|
||||
const Fallback = ({ name }) => <div style={{ // eslint-disable-line react/prop-types
|
||||
padding: "1em",
|
||||
"color": "#aaa"
|
||||
}}>😱 <i>Could not render { name || name === "t" ? name : "this component" }, see the console.</i></div>
|
||||
}}>😱 <i>Could not render { name === "t" ? "this component" : name }, see the console.</i></div>
|
||||
|
||||
const wrapRender = (component) => {
|
||||
const isStateless = component => !(component.prototype && component.prototype.isReactComponent)
|
||||
|
||||
@@ -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 BaseLayout from "core/components/layouts/base"
|
||||
|
||||
import * as LayoutUtils from "core/components/layout-utils"
|
||||
import * as JsonSchemaComponents from "core/json-schema-components"
|
||||
|
||||
@@ -87,6 +89,7 @@ export default function() {
|
||||
model: Model,
|
||||
models: Models,
|
||||
TryItOutButton,
|
||||
BaseLayout
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -2,7 +2,6 @@ import { createStore, applyMiddleware, bindActionCreators, compose } from "redux
|
||||
import Im, { fromJS, Map } from "immutable"
|
||||
import deepExtend from "deep-extend"
|
||||
import { combineReducers } from "redux-immutable"
|
||||
import assign from "object-assign"
|
||||
import serializeError from "serialize-error"
|
||||
import { NEW_THROWN_ERR } from "corePlugins/err/actions"
|
||||
import win from "core/window"
|
||||
@@ -74,7 +73,7 @@ export default class Store {
|
||||
let dispatch = this.getStore().dispatch
|
||||
let getState = this.getStore().getState
|
||||
|
||||
this.boundSystem = assign({},
|
||||
this.boundSystem = Object.assign({},
|
||||
this.getRootInjects(),
|
||||
this.getWrappedAndBoundActions(dispatch),
|
||||
this.getBoundSelectors(getState, this.getSystem),
|
||||
@@ -92,7 +91,7 @@ export default class Store {
|
||||
}
|
||||
|
||||
getRootInjects() {
|
||||
return assign({
|
||||
return Object.assign({
|
||||
getSystem: this.getSystem,
|
||||
getStore: this.getStore.bind(this),
|
||||
getComponents: this.getComponents.bind(this),
|
||||
@@ -251,7 +250,7 @@ export default class Store {
|
||||
|
||||
getMapStateToProps() {
|
||||
return () => {
|
||||
let obj = assign({}, this.getSystem())
|
||||
let obj = Object.assign({}, this.getSystem())
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
+22
-4
@@ -1,5 +1,4 @@
|
||||
import Im from "immutable"
|
||||
import assign from "object-assign"
|
||||
import shallowEqual from "shallowequal"
|
||||
|
||||
import camelCase from "lodash/camelCase"
|
||||
@@ -85,7 +84,7 @@ export function objReduce(obj, fn) {
|
||||
return Object.keys(obj).reduce((newObj, key) => {
|
||||
let res = fn(obj[key], key)
|
||||
if(res && typeof res === "object")
|
||||
assign(newObj, res)
|
||||
Object.assign(newObj, res)
|
||||
return newObj
|
||||
}, {})
|
||||
}
|
||||
@@ -453,13 +452,13 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
|
||||
}
|
||||
|
||||
const validateNumber = ( val ) => {
|
||||
if ( !/^\d+(.?\d+)?$/.test(val)) {
|
||||
if ( !/^-?\d+(.?\d+)?$/.test(val)) {
|
||||
return "Value must be a number"
|
||||
}
|
||||
}
|
||||
|
||||
const validateInteger = ( val ) => {
|
||||
if ( !/^\d+$/.test(val)) {
|
||||
if ( !/^-?\d+$/.test(val)) {
|
||||
return "Value must be integer"
|
||||
}
|
||||
}
|
||||
@@ -559,3 +558,22 @@ export const btoa = (str) => {
|
||||
|
||||
return buffer.toString("base64")
|
||||
}
|
||||
|
||||
export const sorters = {
|
||||
operationsSorter: {
|
||||
alpha: (a, b) => a.get("path").localeCompare(b.get("path")),
|
||||
method: (a, b) => a.get("method").localeCompare(b.get("method"))
|
||||
}
|
||||
}
|
||||
|
||||
export const buildFormData = (data) => {
|
||||
let formArr = []
|
||||
|
||||
for (let name in data) {
|
||||
let val = data[name]
|
||||
if (val !== undefined && val !== "") {
|
||||
formArr.push([name, "=", encodeURIComponent(val).replace(/%20/g,"+")].join(""))
|
||||
}
|
||||
}
|
||||
return formArr.join("&")
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ export default class Topbar extends React.Component {
|
||||
<img height="30" width="30" src={ Logo } alt="Swagger UX"/>
|
||||
<span>swagger</span>
|
||||
</Link>
|
||||
<div className="download-url-wrapper">
|
||||
<form className="download-url-wrapper" onSubmit={this.downloadUrl}>
|
||||
<input className="download-url-input" type="text" onChange={ this.onUrlChange } value={this.state.url} disabled={isLoading} style={inputStyle} />
|
||||
<Button className="download-url-button" onClick={ this.downloadUrl }>Explore</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,28 +13,16 @@ export default class StandaloneLayout extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let { specSelectors, specActions, getComponent } = this.props
|
||||
let { getComponent, specSelectors } = this.props
|
||||
|
||||
let info = specSelectors.info()
|
||||
let url = specSelectors.url()
|
||||
let basePath = specSelectors.basePath()
|
||||
let host = specSelectors.host()
|
||||
let securityDefinitions = specSelectors.securityDefinitions()
|
||||
let externalDocs = specSelectors.externalDocs()
|
||||
let schemes = specSelectors.schemes()
|
||||
|
||||
let Info = getComponent("info")
|
||||
let Operations = getComponent("operations", true)
|
||||
let Models = getComponent("models", true)
|
||||
let AuthorizeBtn = getComponent("authorizeBtn", true)
|
||||
let Container = getComponent("Container")
|
||||
let Row = getComponent("Row")
|
||||
let Col = getComponent("Col")
|
||||
let Errors = getComponent("errors", true)
|
||||
const Schemes = getComponent("schemes")
|
||||
|
||||
const Topbar = getComponent("Topbar", true)
|
||||
const BaseLayout = getComponent("BaseLayout", true)
|
||||
const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true)
|
||||
|
||||
const loadingStatus = specSelectors.loadingStatus()
|
||||
|
||||
return (
|
||||
@@ -56,46 +44,12 @@ export default class StandaloneLayout extends React.Component {
|
||||
<h4 className="title">Failed to load config.</h4>
|
||||
</div>
|
||||
}
|
||||
{ loadingStatus === "success" &&
|
||||
<div>
|
||||
<Errors/>
|
||||
<Row className="information-container">
|
||||
<Col mobile={12}>
|
||||
{ info.count() ? (
|
||||
<Info info={ info } url={ url } host={ host } basePath={ basePath } externalDocs={externalDocs} getComponent={getComponent}/>
|
||||
) : null }
|
||||
</Col>
|
||||
</Row>
|
||||
{ schemes && schemes.size || securityDefinitions ? (
|
||||
<div className="scheme-container">
|
||||
<Col className="schemes wrapper" mobile={12}>
|
||||
{ schemes && schemes.size ? (
|
||||
<Schemes schemes={ schemes } specActions={ specActions } />
|
||||
) : null }
|
||||
{ securityDefinitions ? (
|
||||
<AuthorizeBtn />
|
||||
) : null }
|
||||
</Col>
|
||||
</div>
|
||||
) : null }
|
||||
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
<Operations/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mobile={12} desktop={12} >
|
||||
<Models/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div> }
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<OnlineValidatorBadge />
|
||||
</Col>
|
||||
</Row>
|
||||
{ !loadingStatus || loadingStatus === "success" && <BaseLayout/> }
|
||||
<Row>
|
||||
<Col>
|
||||
<OnlineValidatorBadge />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -502,6 +502,11 @@ body
|
||||
{
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.headerline
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.scheme-container
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
display: flex;
|
||||
|
||||
max-width: 300px;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
flex: 1;
|
||||
@@ -33,8 +35,11 @@
|
||||
{
|
||||
display: flex;
|
||||
|
||||
flex: 3;
|
||||
|
||||
input[type=text]
|
||||
{
|
||||
width: 100%;
|
||||
min-width: 350px;
|
||||
margin: 0;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
README.md
|
||||
deploy.sh
|
||||
@@ -0,0 +1 @@
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
@@ -0,0 +1,3 @@
|
||||
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.
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
# Deploy `swagger-ui-dist` to npm.
|
||||
|
||||
# Parameter Expansion: http://stackoverflow.com/questions/6393551/what-is-the-meaning-of-0-in-a-bash-script
|
||||
cd "${0%/*}"
|
||||
|
||||
# Get UI version
|
||||
UI_VERSION=$(node -p "require('../package.json').version")
|
||||
|
||||
# Replace our version placeholder with UI's version
|
||||
sed -i "s|\$\$VERSION|$UI_VERSION|g" package.json
|
||||
|
||||
# Copy UI's dist files to our directory
|
||||
cp ../dist/* .
|
||||
|
||||
if [ "$PUBLISH_DIST" = "true" ] || [ "$TRAVIS" = "true" ] ; then
|
||||
npm publish .
|
||||
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
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "swagger-ui-dist",
|
||||
"version": "$$VERSION",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
"(in alphabetical order)",
|
||||
"Anna Bodnia <anna.bodnia@gmail.com>",
|
||||
"Buu Nguyen <buunguyen@gmail.com>",
|
||||
"Josh Ponelat <jponelat@gmail.com>",
|
||||
"Kyle Shockey <kyleshockey1@gmail.com>",
|
||||
"Robert Barnwell <robert@robertismy.name>",
|
||||
"Sahar Jafari <shr.jafari@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import { fromJS } from "immutable"
|
||||
import reducer from "corePlugins/spec/reducers"
|
||||
|
||||
describe("spec plugin - reducer", function(){
|
||||
|
||||
describe("update operation value", function() {
|
||||
it("should update the operation at the specified key", () => {
|
||||
const updateOperationValue = reducer["spec_update_operation_value"]
|
||||
|
||||
const state = fromJS({
|
||||
resolved: {
|
||||
"paths": {
|
||||
"/pet": {
|
||||
"post": {
|
||||
"description": "my operation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let result = updateOperationValue(state, {
|
||||
payload: {
|
||||
path: ["/pet", "post"],
|
||||
value: "application/json",
|
||||
key: "consumes_value"
|
||||
}
|
||||
})
|
||||
|
||||
let expectedResult = {
|
||||
resolved: {
|
||||
"paths": {
|
||||
"/pet": {
|
||||
"post": {
|
||||
"description": "my operation",
|
||||
"consumes_value": "application/json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(result.toJS()).toEqual(expectedResult)
|
||||
})
|
||||
|
||||
it("shouldn't throw an error if we try to update the consumes_value of a null operation", () => {
|
||||
const updateOperationValue = reducer["spec_update_operation_value"]
|
||||
|
||||
const state = fromJS({
|
||||
resolved: {
|
||||
"paths": {
|
||||
"/pet": {
|
||||
"post": null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let result = updateOperationValue(state, {
|
||||
payload: {
|
||||
path: ["/pet", "post"],
|
||||
value: "application/json",
|
||||
key: "consumes_value"
|
||||
}
|
||||
})
|
||||
|
||||
expect(result.toJS()).toEqual(state.toJS())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import { fromJS } from "immutable"
|
||||
import { parameterValues, contentTypeValues } from "corePlugins/spec/selectors"
|
||||
import { parameterValues, contentTypeValues, operationScheme } from "corePlugins/spec/selectors"
|
||||
|
||||
describe("spec plugin - selectors", function(){
|
||||
|
||||
@@ -92,4 +92,43 @@ describe("spec plugin - selectors", function(){
|
||||
|
||||
})
|
||||
|
||||
describe("operationScheme", function(){
|
||||
|
||||
it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){
|
||||
// Given
|
||||
let state = fromJS({
|
||||
url: "https://generator.swagger.io/api/swagger.json",
|
||||
resolved: {
|
||||
paths: {
|
||||
"/one": {
|
||||
get: {
|
||||
"consumes_value": "one",
|
||||
"produces_value": "two"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// When
|
||||
let scheme = operationScheme(state, ["/one"], "get")
|
||||
// Then
|
||||
expect(scheme).toEqual("https")
|
||||
})
|
||||
|
||||
// it("should be ok, if no operation found", function(){
|
||||
// // Given
|
||||
// let state = fromJS({ })
|
||||
//
|
||||
// // When
|
||||
// let contentTypes = contentTypeValues(state, [ "/one", "get" ])
|
||||
// // Then
|
||||
// expect(contentTypes.toJS()).toEqual({
|
||||
// requestContentType: undefined,
|
||||
// responseContentType: undefined
|
||||
// })
|
||||
// })
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -22,7 +22,10 @@ module.exports = require('./make-webpack-config.js')({
|
||||
},
|
||||
|
||||
externals: function(context, request, cb) {
|
||||
if(node_modules.indexOf(request) !== -1) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user