提交 f22a6289 编写于 作者: R Ron

in with the new

上级 bd8344c8
{
"presets": [
"es2015",
"react",
"stage-0"
],
"plugins": [
[
"module-alias",
[
{
"expose": "components",
"src": "src/core/components"
},
{
"expose": "core",
"src": "src/core"
},
{
"expose": "img",
"src": "src/img"
},
{
"expose": "corePlugins",
"src": "src/core/plugins"
},
{
"expose": "less",
"src": "src/less"
},
{
"expose": "base",
"src": "npm:getbase/src/less/base"
}
]
]
]
}
node_modules
.idea
.deps_check
.DS_Store
npm-debug.log
Copyright 2017 SmartBear Software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# Swagger UI
[![NPM version](https://badge.fury.io/js/swagger-ui.svg)](http://badge.fury.io/js/swagger-ui)
## New!
This is the new version of swagger-ui, 3.x.
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
## Compatibility
The OpenAPI Specification has undergone 4 revisions since initial creation in 2010. Compatibility between swagger-ui and the OpenAPI Specification is as follows:
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status
------------------ | ------------ | -------------------------- | ----- | ------
3.0.0 | 2017-03-17 | 2.0 | [tag v3.0.0](https://github.com/swagger-api/swagger-ui/tree/v3.0.0) |
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) |
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13) |
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1) |
### How to run
##### Prerequisites
- Node 6.x
- NPM 3.x
If you just want to see your specs, open `public/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`.
##### Browser support
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
## CORS Support
CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + JavaScript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.
You can read about CORS here: http://www.w3.org/TR/cors.
There are two cases where no action is needed for CORS support:
1. swagger-ui is hosted on the same server as the application itself (same host *and* port).
2. The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization.
Otherwise, CORS support needs to be enabled for:
1. Your Swagger docs. For Swagger 2.0 it's the `swagger.json`/`swagger.yaml` and any externally `$ref`ed docs.
2. For the `Try it now` button to work, CORS needs to be enabled on your API endpoints as well.
### Testing CORS Support
You can verify CORS support with one of three techniques:
- Curl your API and inspect the headers. For instance:
```bash
$ curl -I "http://petstore.swagger.io/v2/swagger.json"
HTTP/1.1 200 OK
Date: Sat, 31 Jan 2015 23:05:44 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
Content-Type: application/json
Content-Length: 0
```
This tells us that the petstore resource listing supports OPTIONS, and the following headers: `Content-Type`, `api_key`, `Authorization`.
- Try swagger-ui from your file system and look at the debug console. If CORS is not enabled, you'll see something like this:
```
XMLHttpRequest cannot load http://sad.server.com/v2/api-docs. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
```
Swagger-UI cannot easily show this error state.
- Using the http://www.test-cors.org website. Keep in mind this will show a successful result even if `Access-Control-Allow-Headers` is not available, which is still required for Swagger-UI to function properly.
### Enabling CORS
The method of enabling CORS depends on the server and/or framework you use to host your application. http://enable-cors.org provides information on how to enable CORS in some common web servers.
Other servers/frameworks may provide you information on how to enable it specifically in their use case.
### CORS and Header Parameters
Swagger lets you easily send headers as parameters to requests. The name of these headers *MUST* be supported in your CORS configuration as well. From our example above:
```
Access-Control-Allow-Headers: Content-Type, api_key, Authorization
```
Only headers with these names will be allowed to be sent by Swagger-UI.
## License
Copyright 2017 SmartBear Software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
function extsToRegExp(exts) {
return new RegExp("\\.(" + exts.map(function(ext) {
return ext.replace(/\./g, "\\.");
}).join("|") + ")(\\?.*)?$");
}
module.exports = function loadersByExtension(obj) {
var loaders = [];
Object.keys(obj).forEach(function(key) {
var exts = key.split("|");
var value = obj[key];
var entry = {
extensions: exts,
test: extsToRegExp(exts)
};
if(Array.isArray(value)) {
entry.loaders = value;
} else if(typeof value === "string") {
entry.loader = value;
} else {
Object.keys(value).forEach(function(valueKey) {
entry[valueKey] = value[valueKey];
});
}
loaders.push(entry);
});
return loaders;
};
<!DOCTYPE html>
<!-- this is for the dev server -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<!-- don't be alarmed, these don't match what's in dist, because webpack-dev-server serves them in memory. -->
<script src="/dist/SwaggerUIBundle.js"> </script>
<script src="/dist/SwaggerUIStandalonePreset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
// yay ES6 modules ↘
Array.isArray(SwaggerUIStandalonePreset) ? SwaggerUIStandalonePreset : SwaggerUIStandalonePreset.default
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>
此差异已折叠。
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AA6OA;;;;;;AAoIA;AAm7FA;AAwtCA;AAg0IA;;;;;AAkxBA;AAo8IA;AA41GA;AA23FA;AAmqFA;AA0nFA;AA49CA;AAwhDA;AAkrCA;AAumFA;AAmnHA;;;;;;;;;;;;;;AAqjHA;AAyoIA;AAkuJA;AAilHA;AA4kGA;AAwkEA;AAs3DA;AAovDA;AAotBA;AAoqGA;;;;;;AAueA;AAimGA;AA44EA;;;;;AAoGA;AA2qFA;AAo2CA;AAgvDA;AA8tCA;AAoiEA;AA69FA;;;;;;;;;AA20BA;AA2zIA;AAm4DA","sourceRoot":""}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AAwSA;AAyiGA;AAqwFA;;;;;;AA4eA;AAkvFA;AAu+CA;AAo+CA;AAgrCA;AAgyEA","sourceRoot":""}
\ No newline at end of file
此差异已折叠。
{"version":3,"file":"swagger-ui.css","sources":[],"mappings":"","sourceRoot":""}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;AAooGA;AAw0HA;AAijGA;AA6lCA;AA29BA;AAmwCA;AAw4BA","sourceRoot":""}
\ No newline at end of file
var path = require('path')
var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var deepExtend = require('deep-extend')
var autoprefixer = require('autoprefixer')
var loadersByExtension = require('./build-tools/loadersByExtension')
module.exports = function(options) {
// Special options, that have logic in this file
// ...with defaults
var specialOptions = deepExtend({}, {
hot: false,
separateStylesheets: true,
minimize: false,
longTermCaching: false,
sourcemaps: false,
}, options._special)
var loadersMap = {
'js(x)?': {
loader: 'babel?retainLines=true',
include: [ path.join(__dirname, 'src') ],
},
'json': 'json-loader',
'txt|yaml': 'raw-loader',
'png|jpg|jpeg|gif|svg': specialOptions.disableAssets ? 'null-loader' : 'url-loader?limit=10000',
'woff|woff2': specialOptions.disableAssets ? 'null-loader' : 'url-loader?limit=100000',
'ttf|eot': specialOptions.disableAssets ? 'null-loader' : 'file-loader',
"worker.js": ["worker-loader?inline=true", "babel"]
}
var plugins = []
if( specialOptions.separateStylesheets ) {
plugins.push(new ExtractTextPlugin('[name].css' + (specialOptions.longTermCaching ? '?[contenthash]' : ''), {
allChunks: true
}))
}
if( specialOptions.minimize ) {
plugins.push(
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
}),
new webpack.optimize.DedupePlugin()
)
plugins.push( new webpack.NoErrorsPlugin())
}
plugins.push(
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: specialOptions.minimize ? JSON.stringify('production') : null,
WEBPACK_INLINE_STYLES: !Boolean(specialOptions.separateStylesheets)
},
}))
var cssLoader = 'css-loader!postcss-loader'
var completeStylesheetLoaders = deepExtend({
'css': cssLoader,
'scss': cssLoader + '!' + 'sass-loader?outputStyle=expanded&sourceMap=true&sourceMapContents=true',
'less': cssLoader + '!' + 'less-loader',
}, specialOptions.stylesheetLoaders)
if(specialOptions.cssModules) {
cssLoader = cssLoader + '?module' + (specialOptions.minimize ? '' : '&localIdentName=[path][name]---[local]---[hash:base64:5]')
}
Object.keys(completeStylesheetLoaders).forEach(function(ext) {
var ori = completeStylesheetLoaders[ext]
if(specialOptions.separateStylesheets) {
completeStylesheetLoaders[ext] = ExtractTextPlugin.extract('style-loader', ori)
} else {
completeStylesheetLoaders[ext] = 'style-loader!' + ori
}
})
var loaders = loadersByExtension(deepExtend({}, loadersMap, specialOptions.loaders, completeStylesheetLoaders))
var extraLoaders = (options.module || {} ).loaders
if(Array.isArray(extraLoaders)) {
loaders = loaders.concat(extraLoaders)
delete options.module.loaders
}
var completeConfig = deepExtend({
entry: {},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js',
chunkFilename: '[name].js'
},
target: 'web',
// yaml-js has a reference to `fs`, this is a workaround
node: {
fs: 'empty'
},
module: {
loaders: loaders,
},
resolveLoader: {
root: path.join(__dirname, 'node_modules'),
},
externals: {
'buffertools': true // json-react-schema/deeper depends on buffertools, which fails.
},
resolve: {
root: path.join(__dirname, './src'),
modulesDirectories: ['node_modules'],
extensions: ["", ".web.js", ".js", ".jsx", ".json", ".less"],
packageAlias: 'browser',
alias: {
base: "getbase/src/less/base"
}
},
postcss: function() {
return [autoprefixer]
},
devtool: specialOptions.sourcemaps ? 'cheap-module-source-map' : null,
plugins,
}, options)
return completeConfig
}
{
"name": "swagger-ui",
"version": "3.0.0",
"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",
"scripts": {
"start": "http-server -i -a 0.0.0.0 -p 3001",
"build": "npm run build-core && npm run build-bundle && npm run build-standalone",
"build-bundle": "webpack --config webpack-dist-bundle.config.js --colors",
"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",
"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 dist/",
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv",
"deps-size": "webpack -p --config webpack.check.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt",
"deps-check": "npm run deps-license && npm run deps-size",
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core"
},
"dependencies": {
"brace": "0.7.0",
"btoa": "^1.1.2",
"debounce": "1.0.0",
"deep-extend": "0.4.1",
"expect": "1.20.2",
"getbase": "^2.8.2",
"immutable": "^3.x.x",
"js-yaml": "^3.5.5",
"jsonschema": "^1.1.0",
"less": "2.7.1",
"lodash": "4.17.2",
"matcher": "^0.1.2",
"memoizee": "0.4.1",
"promise-worker": "^1.1.1",
"react": "^15.4.0",
"react-addons-perf": "0.14.8",
"react-addons-shallow-compare": "0.14.8",
"react-addons-test-utils": "0.14.8",
"react-collapse": "2.3.1",
"react-dom": "^15.4.0",
"react-height": "^2.0.0",
"react-hot-loader": "1.3.1",
"react-immutable-proptypes": "2.1.0",
"react-motion": "0.4.4",
"react-object-inspector": "0.2.1",
"react-redux": "^4.x.x",
"react-remarkable": "1.1.1",
"react-split-pane": "0.1.57",
"redux": "^3.x.x",
"redux-immutable": "3.0.8",
"redux-logger": "*",
"reselect": "2.5.3",
"serialize-error": "2.0.0",
"swagger-client": "^3.0.1",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
"xml": "1.0.1",
"yaml-js": "^0.1.3",
"yaml-worker": "^2.1.0"
},
"devDependencies": {
"autoprefixer": "6.6.1",
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.3.2",
"babel-plugin-module-alias": "^1.6.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-es2015-ie": "^6.6.2",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
"babel-runtime": "^6.23.0",
"css-loader": "0.22.0",
"deep-extend": "^0.4.1",
"deepmerge": "^1.3.2",
"extract-text-webpack-plugin": "0.8.2",
"file-loader": "0.8.4",
"html-webpack-plugin": "^2.28.0",
"imports-loader": "0.6.5",
"json-loader": "0.5.3",
"less": "2.5.3",
"less-loader": "2.2.1",
"license-checker": "^8.0.4",
"mocha": "^2.5.3",
"node-sass": "^4.5.0",
"npm-run-all": "3.1.1",
"null-loader": "0.1.1",
"open": "0.0.5",
"postcss-loader": "0.7.0",
"raw-loader": "0.5.1",
"react-hot-loader": "^1.3.1",
"rimraf": "^2.6.0",
"sass-loader": "^6.0.2",
"shallowequal": "0.2.2",
"standard": "^8.6.0",
"standard-loader": "^5.0.0",
"style-loader": "0.13.0",
"url-loader": "0.5.6",
"webpack": "^1.14.0",
"webpack-bundle-size-analyzer": "^2.5.0"
},
"config": {
"deps_check_dir": ".deps_check"
},
"browserslist": [
"> 1%",
"last 2 versions",
"IE 10"
],
"optionalDependencies": {
"webpack-dev-server": "1.14.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="../dist/swagger-ui.css" >
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="../dist/swagger-ui-bundle.js"> </script>
<script src="../dist/swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
// yay ES6 modules ↘
Array.isArray(SwaggerUIStandalonePreset) ? SwaggerUIStandalonePreset : SwaggerUIStandalonePreset.default
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>
<!doctype html>
<html lang="en-US">
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var isValid, qp;
qp = (window.location.hash || location.search).substring(1);
qp = qp ? JSON.parse('{"' + qp.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
createForm(oauth2.auth, qp).submit();
} else {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: "Authorization failed: no accessCode came 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;
}
</script>
/* global ace */
ace.define("ace/snippets/yaml",
["require","exports","module"], function(e,t,n){ // eslint-disable-line no-unused-vars
t.snippetText=undefined
t.scope="yaml"
})
import React, { PropTypes } from "react"
export default class App extends React.Component {
getLayout() {
let { getComponent, layoutSelectors } = this.props
const layoutName = layoutSelectors.current()
const Component = getComponent(layoutName, true)
return Component ? Component : ()=> <h1> No layout defined for "{layoutName}" </h1>
}
render() {
const Layout = this.getLayout()
return (
<Layout/>
)
}
}
App.propTypes = {
getComponent: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired,
}
App.defaultProps = {
}
import React, { PropTypes } from "react"
export default class ApiKeyAuth extends React.Component {
static propTypes = {
authorized: PropTypes.object,
getComponent: PropTypes.func.isRequired,
errSelectors: PropTypes.object.isRequired,
schema: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func
}
constructor(props, context) {
super(props, context)
let { name, schema } = this.props
let value = this.getValue()
this.state = {
name: name,
schema: schema,
value: value
}
}
getValue () {
let { name, authorized } = this.props
return authorized && authorized.getIn([name, "value"])
}
onChange =(e) => {
let { onChange } = this.props
let value = e.target.value
let newState = Object.assign({}, this.state, { value: value })
this.setState(newState)
onChange(newState)
}
render() {
let { schema, getComponent, errSelectors, name } = this.props
const Input = getComponent("Input")
const Row = getComponent("Row")
const Col = getComponent("Col")
const AuthError = getComponent("authError")
const Markdown = getComponent( "Markdown" )
const JumpToPath = getComponent("JumpToPath", true)
let value = this.getValue()
let errors = errSelectors.allErrors().filter( err => err.get("authId") === name)
return (
<div>
<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") } />
</Row>
<Row>
<p>Name: <code>{ schema.get("name") }</code></p>
</Row>
<Row>
<p>In: <code>{ schema.get("in") }</code></p>
</Row>
<Row>
<label>Value:</label>
<Col>
{
value || <Input type="text" onChange={ this.onChange }/>
}
</Col>
</Row>
{
errors.valueSeq().map( (error, key) => {
return <AuthError error={ error }
key={ key }/>
} )
}
</div>
)
}
}
import React, { PropTypes } from "react"
export default class AuthorizationPopup extends React.Component {
close =() => {
let { authActions } = this.props
authActions.showDefinitions(false)
}
render() {
let { authSelectors, authActions, getComponent, errSelectors, specSelectors, fn: { AST } } = this.props
let definitions = authSelectors.shownDefinitions()
const Auths = getComponent("auths")
return (
<div className="dialog-ux">
<div className="backdrop-ux"></div>
<div className="modal-ux">
<div className="modal-dialog-ux">
<div className="modal-ux-inner">
<div className="modal-ux-header">
<h3>Available authorizations</h3>
<button type="button" className="close-modal" onClick={ this.close }>
<svg width="20" height="20">
<use xlinkHref="#close" />
</svg>
</button>
</div>
<div className="modal-ux-content">
{
definitions.valueSeq().map(( definition, key ) => {
return <Auths key={ key }
AST={AST}
definitions={ definition }
getComponent={ getComponent }
errSelectors={ errSelectors }
authSelectors={ authSelectors }
authActions={ authActions }
specSelectors={ specSelectors }/>
})
}
</div>
</div>
</div>
</div>
</div>
)
}
static propTypes = {
fn: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
authSelectors: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
errSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
}
}
import React, { PropTypes } from "react"
export default class AuthorizeBtn extends React.Component {
static propTypes = {
className: PropTypes.string
}
onClick =() => {
let { authActions, authSelectors, errActions} = this.props
let definitions = authSelectors.definitionsToAuthorize()
authActions.showDefinitions(definitions)
}
render() {
let { authSelectors, getComponent } = this.props
//must be moved out of button component
const AuthorizationPopup = getComponent("authorizationPopup", true)
let showPopup = !!authSelectors.shownDefinitions()
let isAuthorized = !!authSelectors.authorized().size
return (
<div className="auth-wrapper">
<button className={isAuthorized ? "btn authorize locked" : "btn authorize unlocked"} onClick={ this.onClick }>
<span>Authorize</span>
<svg width="20" height="20">
<use xlinkHref={ isAuthorized ? "#locked" : "#unlocked" } />
</svg>
</button>
{ showPopup && <AuthorizationPopup /> }
</div>
)
}
static propTypes = {
getComponent: PropTypes.func.isRequired,
authSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
}
}
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
export default class AuthorizeOperationBtn extends React.Component {
onClick =(e) => {
e.stopPropagation()
let { security, authActions, authSelectors } = this.props
let definitions = authSelectors.getDefinitionsByNames(security)
authActions.showDefinitions(definitions)
}
render() {
let { security, authSelectors } = this.props
let isAuthorized = authSelectors.isAuthorized(security)
return (
<button className={isAuthorized ? "authorization__btn locked" : "authorization__btn unlocked"} onClick={ this.onClick }>
<svg width="20" height="20">
<use xlinkHref={ isAuthorized ? "#locked" : "#unlocked" } />
</svg>
</button>
)
}
static propTypes = {
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
security: ImPropTypes.iterable.isRequired
}
}
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
export default class Auths extends React.Component {
static propTypes = {
definitions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired
}
constructor(props, context) {
super(props, context)
this.state = {}
}
onAuthChange =(auth) => {
let { name } = auth
this.setState({ [name]: auth })
}
submitAuth =(e) => {
e.preventDefault()
let { authActions } = this.props
authActions.authorize(this.state)
}
logoutClick =(e) => {
e.preventDefault()
let { authActions, definitions } = this.props
let auths = definitions.map( (val, key) => {
return key
}).toArray()
authActions.logout(auths)
}
render() {
let { definitions, getComponent, authSelectors, errSelectors, specSelectors } = this.props
const ApiKeyAuth = getComponent("apiKeyAuth")
const BasicAuth = getComponent("basicAuth")
const Oauth2 = getComponent("oauth2", true)
const Button = getComponent("Button")
const JumpToPath = getComponent("JumpToPath", true)
let specStr = specSelectors.specStr()
let authorized = authSelectors.authorized()
let authorizedAuth = definitions.filter( (definition, key) => {
return !!authorized.get(key)
})
let nonOauthDefinitions = definitions.filter( schema => schema.get("type") !== "oauth2")
let oauthDefinitions = definitions.filter( schema => schema.get("type") === "oauth2")
return (
<div className="auth-container">
{
!!nonOauthDefinitions.size && <form onSubmit={ this.submitAuth }>
{
nonOauthDefinitions.map( (schema, name) => {
let type = schema.get("type")
let authEl
switch(type) {
case "apiKey": authEl = <ApiKeyAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ this.onAuthChange } />
break
case "basic": authEl = <BasicAuth key={ name }
schema={ schema }
name={ name }
errSelectors={ errSelectors }
authorized={ authorized }
getComponent={ getComponent }
onChange={ this.onAuthChange } />
break
default: authEl = <div key={ name }>Unknown security definition type { type }</div>
}
return (<div key={`${name}-jump`}>
{ authEl }
</div>)
}).toArray()
}
<div className="auth-btn-wrapper">
{
nonOauthDefinitions.size === authorizedAuth.size ? <Button className="btn modal-btn auth" onClick={ this.logoutClick }>Logout</Button>
: <Button type="submit" className="btn modal-btn auth authorize">Authorize</Button>
}
</div>
</form>
}
{
oauthDefinitions && oauthDefinitions.size ? <div>
<div className="scope-def">
<p>Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.</p>
<p>API requires the following scopes. Select which ones you want to grant to Swagger UI.</p>
</div>
{
definitions.filter( schema => schema.get("type") === "oauth2")
.map( (schema, name) =>{
return (<div key={ name }>
<Oauth2 authorized={ authorized }
schema={ schema }
name={ name } />
</div>)
}
).toArray()
}
</div> : null
}
</div>
)
}
static propTypes = {
errSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
authSelectors: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
definitions: ImPropTypes.iterable.isRequired
}
}
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
export default class BasicAuth extends React.Component {
static propTypes = {
authorized: PropTypes.object,
getComponent: PropTypes.func.isRequired,
schema: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired
}
constructor(props, context) {
super(props, context)
let { schema, name } = this.props
let value = this.getValue()
let username = value.username
this.state = {
name: name,
schema: schema,
value: !username ? {} : {
username: username
}
}
}
getValue () {
let { authorized, name } = this.props
return authorized && authorized.getIn([name, "value"]) || {}
}
onChange =(e) => {
let { onChange } = this.props
let { value, name } = e.target
let newValue = this.state.value
newValue[name] = value
this.setState({ value: newValue })
onChange(this.state)
}
render() {
let { schema, getComponent, name, errSelectors } = this.props
const Input = getComponent("Input")
const Row = getComponent("Row")
const Col = getComponent("Col")
const AuthError = getComponent("authError")
const JumpToPath = getComponent("JumpToPath", true)
const Markdown = getComponent( "Markdown" )
let username = this.getValue().username
let errors = errSelectors.allErrors().filter( err => err.get("authId") === name)
return (
<div>
<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") } />
</Row>
<Row>
<Col tablet={2} desktop={2}>username:</Col>
<Col tablet={10} desktop={10}>
{
username || <Input type="text" required="required" name="username" onChange={ this.onChange }/>
}
</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 }
key={ key }/>
} )
}
</div>
)
}
static propTypes = {
name: PropTypes.string.isRequired,
errSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
onChange: PropTypes.func,
schema: ImPropTypes.map,
authorized: ImPropTypes.map
}
}
import React, { PropTypes } from "react"
export default class AuthError extends React.Component {
static propTypes = {
error: PropTypes.object.isRequired
}
render() {
let { error } = this.props
let level = error.get("level")
let message = error.get("message")
let source = error.get("source")
return (
<div className="errors" style={{ backgroundColor: "#ffeeee", color: "red", margin: "1em" }}>
<b style={{ textTransform: "capitalize", marginRight: "1em"}} >{ source } { level }</b>
<span>{ message }</span>
</div>
)
}
}
import React, { PropTypes } from "react"
import oauth2Authorize from "core/oauth2-authorize"
const IMPLICIT = "implicit"
const ACCESS_CODE = "accessCode"
const PASSWORD = "password"
const APPLICATION = "application"
export default class Oauth2 extends React.Component {
static propTypes = {
name: PropTypes.string,
authorized: PropTypes.object,
configs: PropTypes.object,
getComponent: PropTypes.func.isRequired,
schema: PropTypes.object.isRequired,
authSelectors: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
errSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired
}
constructor(props, context) {
super(props, context)
let { name, schema, authorized } = this.props
let auth = authorized && authorized.get(name)
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"
this.state = {
name: name,
schema: schema,
scopes: [],
clientId: clientId,
clientSecret: clientSecret,
username: username,
password: "",
passwordType: passwordType
}
}
authorize =() => {
let { authActions, errActions, getConfigs } = this.props
let configs = getConfigs()
errActions.clear({authId: name,type: "auth", source: "auth"})
oauth2Authorize(this.state, authActions, errActions, configs)
}
onScopeChange =(e) => {
let { target } = e
let { checked } = target
let scope = target.dataset.value
if ( checked && this.state.scopes.indexOf(scope) === -1 ) {
let newScopes = this.state.scopes.concat([scope])
this.setState({ scopes: newScopes })
} else if ( !checked && this.state.scopes.indexOf(scope) > -1) {
this.setState({ scopes: this.state.scopes.filter((val) => val !== scope) })
}
}
onInputChange =(e) => {
let { target : { dataset : { name }, value } } = e
let state = {
[name]: value
}
this.setState(state)
}
logout =(e) => {
e.preventDefault()
let { authActions, errActions, name } = this.props
errActions.clear({authId: name, type: "auth", source: "auth"})
authActions.logout([ name ])
}
render() {
let { schema, getComponent, authSelectors, errSelectors, name } = this.props
const Input = getComponent("Input")
const Row = getComponent("Row")
const Col = getComponent("Col")
const Button = getComponent("Button")
const AuthError = getComponent("authError")
const JumpToPath = getComponent("JumpToPath", true)
const Markdown = getComponent( "Markdown" )
let flow = schema.get("flow")
let scopes = schema.get("allowedScopes") || schema.get("scopes")
let authorizedAuth = authSelectors.authorized().get(name)
let isAuthorized = !!authorizedAuth
let errors = errSelectors.allErrors().filter( err => err.get("authId") === name)
let isValid = !errors.filter( err => err.get("source") === "validation").size
return (
<div>
<h4>OAuth2.0 <JumpToPath path={[ "securityDefinitions", name ]} /></h4>
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
source={ schema.get("description") } />
{ isAuthorized && <h6>Authorized</h6> }
{ ( flow === IMPLICIT || flow === ACCESS_CODE ) && <p>Authorization URL: <code>{ schema.get("authorizationUrl") }</code></p> }
{ ( flow === PASSWORD || flow === ACCESS_CODE || flow === APPLICATION ) && <p>Token URL:<code> { schema.get("tokenUrl") }</code></p> }
<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}>
{
isAuthorized ? <span>{ this.state.username }</span>
: <input type="text" data-name="username" onChange={ this.onInputChange }/>
}
</Col>
</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 === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) &&
( !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"
onChange={ this.onInputChange }/>
}
</Col>
</Row>
}
{
( flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "none") ) && <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"
onChange={ this.onInputChange }/>
}
</Col>
</Row>
}
{
!isAuthorized && flow !== PASSWORD && scopes && scopes.size ? <div className="scopes">
<h2>Scopes:</h2>
{ scopes.map((description, name) => {
return (
<Row key={ name }>
<div className="checkbox">
<Input data-value={ name }
id={`${name}-checkbox`}
disabled={ isAuthorized }
type="checkbox"
onChange={ this.onScopeChange }/>
<label htmlFor={`${name}-checkbox`}>
<span className="item"></span>
<div className="text">
<p className="name">{name}</p>
<p className="description">{description}</p>
</div>
</label>
</div>
</Row>
)
}).toArray()
}
</div> : null
}
{
errors.valueSeq().map( (error, key) => {
return <AuthError error={ error }
key={ key }/>
} )
}
<div className="auth-btn-wrapper">
{ isValid && flow !== APPLICATION &&
( isAuthorized ? <Button className="btn modal-btn auth authorize" onClick={ this.logout }>Logout</Button>
: <Button className="btn modal-btn auth authorize" onClick={ this.authorize }>Authorize</Button>
)
}
</div>
</div>
)
}
}
import React, { Component, PropTypes } from "react"
export default class Clear extends Component {
onClick =() => {
let { specActions, path, method } = this.props
specActions.clearResponse( path, method )
specActions.clearRequest( path, method )
}
render(){
return (
<button className="btn btn-clear opblock-control__btn" onClick={ this.onClick }>
Clear
</button>
)
}
static propTypes = {
specActions: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
}
}
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import { fromJS } from 'immutable'
const noop = ()=>{}
export default class ContentType extends React.Component {
static propTypes = {
contentTypes: PropTypes.oneOfType([ImPropTypes.list, ImPropTypes.set]),
value: PropTypes.string,
onChange: PropTypes.func,
className: PropTypes.string
}
static defaultProps = {
onChange: noop,
value: null,
contentTypes: fromJS(["application/json"]),
}
componentDidMount() {
// Needed to populate the form, initially
this.props.onChange(this.props.contentTypes.first())
}
onChangeWrapper = e => this.props.onChange(e.target.value)
render() {
let { contentTypes, className, value } = this.props
if ( !contentTypes || !contentTypes.size )
return null
return (
<div className={ "content-type-wrapper " + ( className || "" ) }>
<select className="content-type" value={value} onChange={this.onChangeWrapper} >
{ contentTypes.map( (val) => {
return <option key={ val } value={ val }>{ val }</option>
}).toArray()}
</select>
</div>
)
}
}
import React, { PropTypes } from "react"
import curlify from "core/curlify"
export default class Curl extends React.Component {
static propTypes = {
request: PropTypes.object.isRequired
}
handleFocus(e) {
e.target.select()
document.execCommand("copy")
}
render() {
let { request } = this.props
let curl = curlify(request)
return (
<div>
<h4>Curl</h4>
<div className="copy-paste">
<textarea onFocus={this.handleFocus} className="curl" style={{ whiteSpace: "normal" }} defaultValue={curl}></textarea>
</div>
</div>
)
}
}
import React, { PropTypes } from "react"
import Collapse from "react-collapse"
import { presets } from "react-motion"
import ObjectInspector from "react-object-inspector"
import Perf from "react-addons-perf"
export default class Debug extends React.Component {
constructor() {
super()
this.state = {
jsonDumpOpen: false
}
this.toggleJsonDump = (e) => {
e.preventDefault()
this.setState({jsonDumpOpen: !this.state.jsonDumpOpen})
}
window.Perf = Perf
}
plusOrMinus(bool) {
return bool ? "-" : "+"
}
render() {
let { getState } = this.props
window.props = this.props
return (
<div className="info">
<h3><a onClick={this.toggleJsonDump}> {this.plusOrMinus(this.state.jsonDumpOpen)} App </a></h3>
<Collapse isOpened={this.state.jsonDumpOpen} springConfig={presets.noWobble}>
<ObjectInspector data={getState().toJS() || {}} name="state" initialExpandedPaths={["state"]}/>
</Collapse>
</div>
)
}
}
Debug.propTypes = {
getState: PropTypes.func.isRequired
}
import React, { PropTypes } from "react"
import Im, { List } from "immutable"
import Collapse from "react-collapse"
import sortBy from "lodash/sortBy"
export default class Errors extends React.Component {
static propTypes = {
jumpToLine: PropTypes.func,
errSelectors: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired
}
render() {
let { jumpToLine, errSelectors, layoutSelectors, layoutActions } = this.props
let errors = errSelectors.allErrors()
// all thrown errors, plus error-level everything else
let allErrorsToDisplay = errors.filter(err => err.get("type") === "thrown" ? true :err.get("level") === "error")
if(!allErrorsToDisplay || allErrorsToDisplay.count() < 1) {
return null
}
let isVisible = layoutSelectors.isShown(["errorPane"], true)
let toggleVisibility = () => layoutActions.show(["errorPane"], !isVisible)
let sortedJSErrors = allErrorsToDisplay.sortBy(err => err.get("line"))
return (
<pre className="errors-wrapper">
<hgroup className="error">
<h4 className="errors__title">Errors</h4>
<button className="btn errors__clear-btn" onClick={ toggleVisibility }>{ isVisible ? "Hide" : "Show" }</button>
</hgroup>
<Collapse isOpened={ isVisible } animated >
<div className="errors">
{ sortedJSErrors.map((err, i) => {
if(err.get("type") === "thrown") {
return <ThrownErrorItem key={ i } error={ err.get("error") || err } jumpToLine={jumpToLine} />
}
if(err.get("type") === "spec") {
return <SpecErrorItem key={ i } error={ err } jumpToLine={jumpToLine} />
}
}) }
</div>
</Collapse>
</pre>
)
}
}
const ThrownErrorItem = ( { error, jumpToLine } ) => {
if(!error) {
return null
}
let errorLine = error.get("line")
return (
<div className="error-wrapper">
{ !error ? null :
<div>
<h4>{ (error.get("source") && error.get("level")) ?
toTitleCase(error.get("source")) + " " + error.get("level") : "" }
{ error.get("path") ? <small> at {error.get("path")}</small>: null }</h4>
<span style={{ whiteSpace: "pre-line", "maxWidth": "100%" }}>
{ error.get("message") }
</span>
<div>
{ errorLine ? <a onClick={jumpToLine.bind(null, errorLine)}>Jump to line { errorLine }</a> : null }
</div>
</div>
}
</div>
)
}
const SpecErrorItem = ( { error, jumpToLine } ) => {
return (
<div className="error-wrapper">
{ !error ? null :
<div>
<h4>{ toTitleCase(error.get("source")) + " " + error.get("level") }{ error.get("path") ? <small> at {List.isList(error.get("path")) ? error.get("path").join(".") : error.get("path")}</small>: null }</h4>
<span style={{ whiteSpace: "pre-line"}}>{ error.get("message") }</span>
<div>
{ jumpToLine ? (
<a onClick={jumpToLine.bind(null, error.get("line"))}>Jump to line { error.get("line") }</a>
) : null }
</div>
</div>
}
</div>
)
}
function toTitleCase(str) {
return str
.split(" ")
.map(substr => substr[0].toUpperCase() + substr.slice(1))
.join(" ")
}
ThrownErrorItem.propTypes = {
error: PropTypes.object.isRequired,
jumpToLine: PropTypes.func
}
SpecErrorItem.propTypes = {
error: PropTypes.object.isRequired,
jumpToLine: PropTypes.func
}
import React, { Component, PropTypes } from "react"
import { fromJS } from "immutable"
export default class Execute extends Component {
static propTypes = {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
operation: PropTypes.object.isRequired,
path: PropTypes.string.isRequired,
getComponent: PropTypes.func.isRequired,
method: PropTypes.string.isRequired,
onExecute: PropTypes.func
}
onClick=()=>{
let { specSelectors, specActions, operation, path, method } = this.props
specActions.validateParams( [path, method] )
if ( specSelectors.validateBeforeExecute([path, method]) ) {
if(this.props.onExecute) {
this.props.onExecute()
}
specActions.execute( { operation, path, method } )
}
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue([this.props.path, this.props.method], val)
render(){
let { getComponent, operation, specActions, path, method } = this.props
const ContentType = getComponent( "contentType" )
return (
<button className="btn execute opblock-control__btn" onClick={ this.onClick }>
Execute
</button>
)
}
}
import React from "react"
export default class Footer extends React.Component {
render() {
return (
<div className="footer"></div>
)
}
}
import React, { PropTypes } from "react"
import Im from "immutable"
export default class Headers extends React.Component {
static propTypes = {
headers: PropTypes.object.isRequired
};
render() {
let { headers } = this.props
if ( !headers || !headers.size )
return null
return (
<div className="headers-wrapper">
<h4 className="headers__title">Headers:</h4>
<table className="headers">
<thead>
<tr className="header-row">
<th className="header-col">Name</th>
<th className="header-col">Description</th>
<th className="header-col">Type</th>
</tr>
</thead>
<tbody>
{
headers.entrySeq().map( ([ key, header ]) => {
if(!Im.Map.isMap(header)) {
return null
}
return (<tr key={ key }>
<td className="header-col">{ key }</td>
<td className="header-col">{ header.get( "description" ) }</td>
<td className="header-col">{ header.get( "type" ) }</td>
</tr>)
}).toArray()
}
</tbody>
</table>
</div>
)
}
}
import React, { Component, PropTypes } from "react"
import { highlight } from "core/utils"
export default class HighlightCode extends Component {
static propTypes = {
value: PropTypes.string.isRequired,
className: PropTypes.string
}
componentDidMount() {
highlight(this.refs.el)
}
componentDidUpdate() {
highlight(this.refs.el)
}
render () {
let { value, className } = this.props
className = className || ""
return <pre ref="el" className={className + " microlight"}>{ value }</pre>
}
}
import React, { PropTypes } from "react"
import { fromJS } from "immutable"
import ImPropTypes from "react-immutable-proptypes"
class Path extends React.Component {
static propTypes = {
host: PropTypes.string,
basePath: PropTypes.string
}
render() {
let { host, basePath } = this.props
return (
<pre className="base-url">
[ Base url: {host}{basePath}]
</pre>
)
}
}
class Contact extends React.Component {
static propTypes = {
data: PropTypes.object
}
render(){
let { data } = this.props
let name = data.get("name") || "the developer"
let url = data.get("url")
let email = data.get("email")
return (
<div>
{ url && <div><a href={ url } target="_blank">{ name } - Website</a></div> }
{ email &&
<a href={`mailto:${email}`}>
{ url ? `Send email to ${name}` : `Contact ${name}`}
</a>
}
</div>
)
}
}
class License extends React.Component {
static propTypes = {
license: PropTypes.object
}
render(){
let { license } = this.props
let name = license.get("name") || "License"
let url = license.get("url")
return (
<div>
{
url ? <a href={ url }>{ name }</a>
: <span>{ name }</span>
}
</div>
)
}
}
export default class Info extends React.Component {
static propTypes = {
info: PropTypes.object,
url: PropTypes.string,
host: PropTypes.string,
basePath: PropTypes.string,
externalDocs: ImPropTypes.map,
getComponent: PropTypes.func.isRequired,
}
render() {
let { info, url, host, basePath, getComponent, externalDocs } = this.props
let version = info.get("version")
let description = info.get("description")
let title = info.get("title")
let termsOfService = info.get("termsOfService")
let contact = info.get("contact")
let license = info.get("license")
const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()
const Markdown = getComponent("Markdown")
return (
<div className="info">
<hgroup className="main">
<h2 className="title" >{ title }
{ version && <small><pre className="version"> { version } </pre></small> }
</h2>
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
{ url && <a href={ url }><span className="url"> { url } </span></a> }
</hgroup>
<div className="description">
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} source={ description } />
</div>
{
termsOfService && <div>
<a href={ termsOfService }>Terms of service</a>
</div>
}
{ contact && contact.size ? <Contact data={ contact } /> : null }
{ license && license.size ? <License license={ license } /> : null }
{ externalDocsUrl ?
<a target="_blank" href={externalDocsUrl}>{externalDocsDescription || externalDocsUrl}</a>
: null }
</div>
)
}
}
Info.propTypes = {
title: PropTypes.any,
description: PropTypes.any,
version: PropTypes.any,
url: PropTypes.string
}
import React, { PropTypes } from "react"
import OriCollapse from "react-collapse"
import _Markdown from "react-remarkable"
const noop = () => {}
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
// Normal element
if(fullscreen)
return <section {...rest}/>
let containerClass = "container" + (full ? "-full" : "")
return (
<section {...rest} className={xclass(rest.className, containerClass)}/>
)
}
}
Container.propTypes = {
fullscreen: PropTypes.bool,
full: PropTypes.bool,
className: PropTypes.string
}
const DEVICES = {
"mobile": "",
"tablet": "-tablet",
"desktop": "-desktop",
"large": "-hd"
}
export class Col extends React.Component {
render() {
const {
hide,
keepContents,
mobile, /* we don't want these in the final component, since React now complains. So we extract them */
tablet,
desktop,
large,
...rest
} = this.props
if(hide && !keepContents)
return <span/>
let classesAr = []
for (let device in DEVICES) {
let deviceClass = DEVICES[device]
if(device in this.props) {
let val = this.props[device]
if(val < 1) {
classesAr.push("none" + deviceClass)
continue
}
classesAr.push("block" + deviceClass)
classesAr.push("col-" + val + deviceClass)
}
}
let classes = xclass(rest.className, "clear", ...classesAr)
return (
<section {...rest} style={{display: hide ? "none": null}} className={classes}/>
)
}
}
Col.propTypes = {
hide: PropTypes.bool,
keepContents: PropTypes.bool,
mobile: PropTypes.number,
tablet: PropTypes.number,
desktop: PropTypes.number,
large: PropTypes.number,
className: PropTypes.string
}
export class Row extends React.Component {
render() {
return <div {...this.props} className={xclass(this.props.className, "wrapper")} />
}
}
Row.propTypes = {
className: PropTypes.string
}
export class Button extends React.Component {
static propTypes = {
className: PropTypes.string
}
static defaultProps = {
className: ""
}
render() {
return <button {...this.props} className={xclass(this.props.className, "button")} />
}
}
export const TextArea = (props) => <textarea {...props} />
export const Input = (props) => <input {...props} />
export class Select extends React.Component {
static propTypes = {
allowedValues: PropTypes.object,
value: PropTypes.any,
onChange: PropTypes.func,
multiple: PropTypes.bool,
allowEmptyValue: PropTypes.bool
}
static defaultProps = {
multiple: false,
allowEmptyValue: true
}
constructor(props, context) {
super(props, context)
let value
if (props.value !== undefined) {
value = props.value
} else {
value = props.multiple ? [""] : ""
}
this.state = { value: value }
}
onChange = (e) => {
let { onChange, multiple } = this.props
let options = [].slice.call(e.target.options)
let value
if (multiple) {
value = options.filter(function (option) {
return option.selected
})
.map(function (option){
return option.value
})
} else {
value = e.target.value
}
this.setState({value: value})
onChange && onChange(value)
}
render(){
let { allowedValues, multiple, allowEmptyValue } = this.props
let value = this.state.value.toJS ? this.state.value.toJS() : this.state.value
return (
<select multiple={ multiple } value={ value } onChange={ this.onChange } >
{ allowEmptyValue ? <option value="">--</option> : null }
{
allowedValues.map(function (item, key) {
return <option key={ key } value={ String(item) }>{ item }</option>
})
}
</select>
)
}
}
export class Link extends React.Component {
render() {
return <a {...this.props} className={xclass(this.props.className, "link")}/>
}
}
Link.propTypes = {
className: PropTypes.string
}
const NoMargin = ({children}) => <div style={{height: "auto", border: "none", margin: 0, padding: 0}}> {children} </div>
NoMargin.propTypes = {
children: PropTypes.node
}
export class Collapse extends React.Component {
static propTypes = {
isOpened: PropTypes.bool,
children: PropTypes.node.isRequired,
animated: PropTypes.bool
}
static defaultProps = {
isOpened: false,
animated: false
}
renderNotAnimated() {
if(!this.props.isOpened)
return <noscript/>
return (
<NoMargin>
{this.props.children}
</NoMargin>
)
}
render() {
let { animated, isOpened, children } = this.props
if(!animated)
return this.renderNotAnimated()
children = isOpened ? children : null
return (
<OriCollapse isOpened={isOpened}>
<NoMargin>
{children}
</NoMargin>
</OriCollapse>
)
}
}
import React, { PropTypes } from "react"
export default class XPane extends React.Component {
render() {
let { getComponent, specSelectors, specActions, layoutSelectors, layoutActions } = this.props
let info = specSelectors.info()
let url = specSelectors.url()
let showEditor = layoutSelectors.isShown("editor")
let Info = getComponent("info")
let Operations = getComponent("operations", true)
let Overview = getComponent("overview", true)
let Editor = getComponent("editor", true)
let Footer = getComponent("footer", true)
let Header = getComponent("header", true)
let Container = getComponent("Container")
let Row = getComponent("Row")
let Col = getComponent("Col")
let Button = getComponent("Button")
let showEditorAction = ()=> layoutActions.show("editor", !showEditor)
return (
<Container fullscreen>
<Header/>
{
info && info.size ? <Info version={info.get("version")}
description={info.get("description")}
title={info.get("title")}
url={url}/>
: null
}
<Button onClick={showEditorAction}>{showEditor ? "Hide" : "Show"} Editor</Button>
<Button onClick={specActions.formatIntoYaml}>Format contents</Button>
<Row>
<Col desktop={3} >
<Overview/>
</Col>
<Col hide={!showEditor} keepContents={true} desktop={5} >
<Editor/>
</Col>
<Col desktop={showEditor ? 4 : 9} >
<Operations/>
</Col>
</Row>
<Footer></Footer>
</Container>
)
}
}
XPane.propTypes = {
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired
}
import React, { PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
const Headers = ( { headers } )=>{
return (
<div>
<h5>Response headers</h5>
<pre>{headers}</pre>
</div>)
}
Headers.propTypes = {
headers: PropTypes.array.isRequired
}
export default class LiveResponse extends React.Component {
static propTypes = {
response: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
render() {
let { request, response, getComponent } = this.props
const Curl = getComponent("curl")
let body = response.get("text")
let status = response.get("status")
let url = response.get("url")
let originalHeaders = response.get("headers")
let headers = originalHeaders && originalHeaders.toJS()
let headersKeys = Object.keys(headers)
let returnObject = headersKeys.map(key => {
return <span className="headerline" key={key}> {key}: {headers[key]} </span>
})
let notDocumented = response.get("notDocumented")
let ResponseBody = getComponent("responseBody")
let contentType = headers && headers["content-type"]
let isError = response.get("error")
return (
<div>
{ request && <Curl request={ request }/> }
<h4>Server response</h4>
<table className="responses-table">
<thead>
<tr className="responses-header">
<td className="col col_header response-col_status">Code</td>
<td className="col col_header response-col_description">Details</td>
</tr>
</thead>
<tbody>
<tr className="response">
<td className="col response-col_status">
{ status }
{
!notDocumented ? null :
<div className="response-undocumented">
<i> Undocumented </i>
</div>
}
</td>
<td className="col response-col_description">
{
!isError ? null : <span>
{`${response.get("name")}: ${response.get("message")}`}
</span>
}
{
!body || isError ? null
: <ResponseBody content={ body }
contentType={ contentType }
url={ url }
headers={ headers }
getComponent={ getComponent }/>
}
{
!headers ? null : <Headers headers={ returnObject }/>
}
</td>
</tr>
</tbody>
</table>
</div>
)
}
static propTypes = {
getComponent: PropTypes.func.isRequired,
request: ImPropTypes.map,
response: ImPropTypes.map
}
}
import React, { PropTypes } from "react"
export default class ModelExample extends React.Component {
static propTypes = {
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
schema: PropTypes.object.isRequired,
example: PropTypes.any.isRequired,
isExecute: PropTypes.bool
}
constructor(props, context) {
super(props, context)
this.state = {
activeTab: "example"
}
}
activeTab =( e ) => {
let { target : { dataset : { name } } } = e
this.setState({
activeTab: name
})
}
render() {
let { getComponent, specSelectors, schema, example, isExecute } = this.props
const Model = getComponent("model")
return <div>
<ul className="tab">
<li className={ "tabitem" + ( isExecute || this.state.activeTab === "example" ? " active" : "") }>
<a className="tablinks" data-name="example" onClick={ this.activeTab }>Example Value</a>
</li>
<li className={ "tabitem" + ( !isExecute && this.state.activeTab === "model" ? " active" : "") }>
<a className={ "tablinks" + ( isExecute ? " inactive" : "" )} data-name="model" onClick={ this.activeTab }>Model</a>
</li>
</ul>
<div>
{
(isExecute || this.state.activeTab === "example") && example
}
{
!isExecute && this.state.activeTab === "model" && <Model schema={ schema }
getComponent={ getComponent }
specSelectors={ specSelectors }
expandDepth={ 1 } />
}
</div>
</div>
}
}
import React, { Component, PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import isObject from "lodash/isObject"
import { List } from "immutable"
const braceOpen = "{"
const braceClose = "}"
const EnumModel = ({ value }) => {
let collapsedContent = <span>Array [ { value.count() } ]</span>
return <span className="prop-enum">
Enum:<br />
<Collapse collapsedContent={ collapsedContent }>
[ { value.join(", ") } ]
</Collapse>
</span>
}
EnumModel.propTypes = {
value: ImPropTypes.iterable
}
class ObjectModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
expandDepth: PropTypes.number,
depth: PropTypes.number
}
render(){
let { schema, name, isRef, getComponent, depth, ...props } = this.props
let { expandDepth } = this.props
const JumpToPath = getComponent("JumpToPath", true)
let description = schema.get("description")
let properties = schema.get("properties")
let additionalProperties = schema.get("additionalProperties")
let title = schema.get("title") || name
let required = schema.get("required")
const JumpToPathSection = ({ name }) => <span className="model-jump-to-path"><JumpToPath path={`definitions.${name}`} /></span>
let collapsedContent = (<span>
<span>{ braceOpen }</span>...<span>{ braceClose }</span>
{
isRef ? <JumpToPathSection name={ name }/> : ""
}
</span>)
return <span className="model">
{
title && <span className="model-title">
{ isRef && schema.get("$$ref") && <span className="model-hint">{ schema.get("$$ref") }</span> }
<span className="model-title__text">{ title }</span>
</span>
}
<Collapse collapsed={ depth > expandDepth } collapsedContent={ collapsedContent }>
<span className="brace-open object">{ braceOpen }</span>
{
!isRef ? null : <JumpToPathSection name={ name }/>
}
<span className="inner-object">
{
<table className="model" style={{ marginLeft: "2em" }}><tbody>
{
!description ? null : <tr style={{ color: "#999", fontStyle: "italic" }}>
<td>description:</td>
<td>{ description }</td>
</tr>
}
{
!(properties && properties.size) ? null : properties.entrySeq().map(
([key, value]) => {
let isRequired = List.isList(required) && required.contains(key)
let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" }
if ( isRequired ) {
propertyStyle.fontWeight = "bold"
}
return (<tr key={key}>
<td style={ propertyStyle }>{ key }:</td>
<td style={{ verticalAlign: "top" }}>
<Model key={ `object-${name}-${key}_${value}` } { ...props }
required={ isRequired }
getComponent={ getComponent }
schema={ value }
depth={ depth + 1 } />
</td>
</tr>)
}).toArray()
}
{
!additionalProperties || !additionalProperties.size ? null
: <tr>
<td>{ "< * >:" }</td>
<td>
<Model { ...props } required={ false }
getComponent={ getComponent }
schema={ additionalProperties }
depth={ depth + 1 } />
</td>
</tr>
}
</tbody></table>
}
</span>
<span className="brace-close">{ braceClose }</span>
</Collapse>
</span>
}
}
class Primitive extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
required: PropTypes.bool
}
render(){
let { schema, required } = this.props
if(!schema || !schema.get) {
// don't render if schema isn't correctly formed
return <div></div>
}
let type = schema.get("type")
let format = schema.get("format")
let xml = schema.get("xml")
let enumArray = schema.get("enum")
let description = schema.get("description")
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "$$ref"].indexOf(key) === -1 )
let style = required ? { fontWeight: "bold" } : {}
let propStyle = { color: "#999", fontStyle: "italic" }
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>)
: null
}
{
xml && xml.size ? (<span><br /><span style={ propStyle }>xml:</span>
{
xml.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }><br/>&nbsp;&nbsp;&nbsp;{key}: { String(v) }</span>).toArray()
}
</span>): null
}
{
enumArray && <EnumModel value={ enumArray } />
}
</span>
}
}
class ArrayModel extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
required: PropTypes.bool,
expandDepth: PropTypes.number,
depth: PropTypes.number
}
render(){
let { required, schema, depth, expandDepth } = this.props
let items = schema.get("items")
return <span>
<Collapse collapsed={ depth > expandDepth } collapsedContent="[...]">
[
<span><Model { ...this.props } schema={ items } required={ false }/></span>
]
</Collapse>
{ required && <span style={{ color: "red" }}>*</span>}
</span>
}
}
class Model extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
required: PropTypes.bool,
expandDepth: PropTypes.number,
depth: PropTypes.number
}
getModelName =( ref )=> {
if ( ref.indexOf("#/definitions/") !== -1 ) {
return ref.replace(/^.*#\/definitions\//, "")
}
}
getRefSchema =( model )=> {
let { specSelectors } = this.props
return specSelectors.findDefinition(model)
}
render () {
let { schema, required, name, isRef } = this.props
let $$ref = schema && schema.get("$$ref")
let modelName = $$ref && this.getModelName( $$ref )
let modelSchema, type
if ( schema && (schema.get("type") || schema.get("properties")) ) {
modelSchema = schema
} else if ( $$ref ) {
modelSchema = this.getRefSchema( modelName )
}
type = modelSchema && modelSchema.get("type")
if ( !type && modelSchema && modelSchema.get("properties") ) {
type = "object"
}
switch(type) {
case "object":
return <ObjectModel className="object" { ...this.props } schema={ modelSchema }
name={ modelName || name }
isRef={ isRef!== undefined ? isRef : !!$$ref }/>
case "array":
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } required={ required } />
case "string":
case "number":
case "integer":
case "boolean":
default:
return <Primitive schema={ modelSchema } required={ required }/>
}
}
}
export default class ModelComponent extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
name: PropTypes.string,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
expandDepth: PropTypes.number
}
render(){
let { name, schema } = this.props
let title = schema.get("title") || name
return <div className="model-box">
<Model { ...this.props } depth={ 1 } expandDepth={ this.props.expandDepth || 0 }/>
</div>
}
}
class Collapse extends Component {
static propTypes = {
collapsedContent: PropTypes.any,
collapsed: PropTypes.bool,
children: PropTypes.any
}
static defaultProps = {
collapsedContent: "{...}",
collapsed: true,
}
constructor(props, context) {
super(props, context)
let { collapsed, collapsedContent } = this.props
this.state = {
collapsed: collapsed !== undefined ? collapsed : Collapse.defaultProps.collapsed,
collapsedContent: collapsedContent || Collapse.defaultProps.collapsedContent
}
}
toggleCollapsed=()=>{
this.setState({
collapsed: !this.state.collapsed
})
}
render () {
return (<span>
<span onClick={ this.toggleCollapsed } style={{ "cursor": "pointer" }}>
<span className={ "model-toggle" + ( this.state.collapsed ? " collapsed" : "" ) }></span>
</span>
{ this.state.collapsed ? this.state.collapsedContent : this.props.children }
</span>)
}
}
import React, { Component, PropTypes } from "react"
export default class Models extends Component {
static propTypes = {
getComponent: PropTypes.func,
specSelectors: PropTypes.object
}
render(){
let { specSelectors, getComponent, layoutSelectors, layoutActions } = this.props
let definitions = specSelectors.definitions()
let showModels = layoutSelectors.isShown('models', true)
const Model = getComponent("model")
const Collapse = getComponent("Collapse")
if (!definitions.size) return null
return <section className={ showModels ? "models is-open" : "models"}>
<h4 onClick={() => layoutActions.show('models', !showModels)}>
<span>Models</span>
<svg width="20" height="20">
<use xlinkHref="#large-arrow" />
</svg>
</h4>
<Collapse isOpened={showModels} animated>
{
definitions.entrySeq().map( ( [ name, model ])=>{
return <div className="model-container" key={ `models-section-${name}` }>
<Model name={ name }
schema={ model }
isRef={ true }
getComponent={ getComponent }
specSelectors={ specSelectors }/>
</div>
}).toArray()
}
</Collapse>
</section>
}
}
import React from "react"
export default class OnlineValidatorBadge extends React.Component {
constructor(props, context) {
super(props, context)
let { specSelectors, getConfigs } = props
let { validatorUrl } = getConfigs()
this.state = {
url: specSelectors.url(),
validatorUrl: validatorUrl
}
}
componentWillReceiveProps(nextProps) {
let { specSelectors, getConfigs } = nextProps
let { validatorUrl } = getConfigs()
this.setState({
url: specSelectors.url(),
validatorUrl: validatorUrl
})
}
render() {
let { getConfigs } = this.props
let { spec } = getConfigs()
if ( typeof spec === "object" && Object.keys(spec).length) return null
if (!this.state.url) {
return null
}
return (<span style={{ float: "right"}}>
<a target="_blank" href={`${ this.state.validatorUrl }/debug?url=${ this.state.url }`}>
<img alt="Online validator badge" src={`${ this.state.validatorUrl }?url=${ this.state.url }`} />
</a>
</span>)
}
}
import React, { PropTypes } from "react"
import { Map, fromJS } from "immutable"
import shallowCompare from "react-addons-shallow-compare"
import { getList } from "core/utils"
import * as CustomPropTypes from "core/proptypes"
//import "less/opblock"
export default class Operation extends React.Component {
static propTypes = {
path: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
operation: PropTypes.object.isRequired,
showSummary: PropTypes.bool,
isShownKey: CustomPropTypes.arrayOrString.isRequired,
jumpToKey: CustomPropTypes.arrayOrString.isRequired,
allowTryItOut: PropTypes.bool,
response: PropTypes.object,
request: PropTypes.object,
getComponent: PropTypes.func.isRequired,
authActions: PropTypes.object,
authSelectors: PropTypes.object,
specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired
}
static defaultProps = {
showSummary: true,
response: null,
allowTryItOut: true,
}
constructor(props, context) {
super(props, context)
this.state = {
tryItOutEnabled: false
}
}
componentWillReceiveProps(nextProps) {
const defaultContentType = "application/json"
let { specActions, path, method, operation } = nextProps
let producesValue = operation.get("produces_value")
let produces = operation.get("produces")
let consumes = operation.get("consumes")
let consumesValue = operation.get("consumes_value")
if(nextProps.response !== this.props.response) {
this.setState({ executeInProgress: false })
}
if (producesValue === undefined) {
producesValue = produces && produces.size ? produces.first() : defaultContentType
specActions.changeProducesValue([path, method], producesValue)
}
if (consumesValue === undefined) {
consumesValue = consumes && consumes.size ? consumes.first() : defaultContentType
specActions.changeConsumesValue([path, method], consumesValue)
}
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
toggleShown =() => {
let { layoutActions, isShownKey } = this.props
layoutActions.show(isShownKey, !this.isShown())
}
isShown =() => {
let { layoutSelectors, isShownKey } = this.props
return layoutSelectors.isShown(isShownKey, false ) // Here is where we set the default
}
onTryoutClick =() => {
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
}
onCancelClick =() => {
let { specActions, path, method } = this.props
this.setState({tryItOutEnabled: !this.state.tryItOutEnabled})
specActions.clearValidateParams([path, method])
}
onExecute = () => {
this.setState({ executeInProgress: true })
}
render() {
let {
isShownKey,
jumpToKey,
path,
method,
operation,
showSummary,
response,
request,
allowTryItOut,
fn,
getComponent,
specActions,
specSelectors,
authActions,
authSelectors,
layoutSelectors,
layoutActions,
} = this.props
let summary = operation.get("summary")
let description = operation.get("description")
let deprecated = operation.get("deprecated")
let externalDocs = operation.get("externalDocs")
let responses = operation.get("responses")
let security = operation.get("security") || specSelectors.security()
let produces = operation.get("produces")
let schemes = operation.get("schemes")
let parameters = getList(operation, ["parameters"])
const Responses = getComponent("responses")
const Parameters = getComponent( "parameters" )
const Execute = getComponent( "execute" )
const Clear = getComponent( "clear" )
const AuthorizeOperationBtn = getComponent( "authorizeOperationBtn" )
const JumpToPath = getComponent("JumpToPath", true)
const Collapse = getComponent( "Collapse" )
const Markdown = getComponent( "Markdown" )
const Schemes = getComponent( "schemes" )
// Merge in Live Response
if(response && response.size > 0) {
let notDocumented = !responses.get(String(response.get("status")))
response = response.set("notDocumented", notDocumented)
}
let { tryItOutEnabled } = this.state
let shown = this.isShown()
let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )
return (
<div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey} >
<div className={`opblock-summary opblock-summary-${method}`} onClick={this.toggleShown} >
<span className="opblock-summary-method">{method.toUpperCase()}</span>
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
<span>{path}</span>
<JumpToPath path={jumpToKey} />
</span>
{ !showSummary ? null :
<div className="opblock-summary-description">
{ summary }
</div>
}
{
(!security || !security.count()) ? null :
<AuthorizeOperationBtn authActions={ authActions }
security={ security }
authSelectors={ authSelectors }/>
}
</div>
<Collapse isOpened={shown} animated>
<div className="opblock-body">
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
{ description &&
<div className="opblock-description-wrapper">
<div className="opblock-description">
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} source={ description } />
</div>
</div>
}
{
externalDocs && externalDocs.get("url") ?
<div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs">
<span className="opblock-external-docs__description">{ externalDocs.get("description") }</span>
<a className="opblock-external-docs__link" href={ externalDocs.get("url") }>{ externalDocs.get("url") }</a>
</div>
</div> : null
}
<Parameters
parameters={parameters}
onChangeKey={onChangeKey}
onTryoutClick = { this.onTryoutClick }
onCancelClick = { this.onCancelClick }
tryItOutEnabled = { tryItOutEnabled }
allowTryItOut={allowTryItOut}
fn={fn}
getComponent={ getComponent }
specActions={ specActions }
specSelectors={ specSelectors }
pathMethod={ [path, method] }
/>
{!tryItOutEnabled || !allowTryItOut ? null : schemes && schemes.size ? <Schemes schemes={ schemes }
path={ path }
method={ method }
specActions={ specActions }/>
: null
}
<div className={(!tryItOutEnabled || !response || !allowTryItOut) ? "execute-wrapper" : "btn-group"}>
{ !tryItOutEnabled || !allowTryItOut ? null :
<Execute
getComponent={getComponent}
operation={ operation }
specActions={ specActions }
specSelectors={ specSelectors }
path={ path }
method={ method }
onExecute={ this.onExecute } />
}
{ (!tryItOutEnabled || !response || !allowTryItOut) ? null :
<Clear
onClick={ this.onClearClick }
specActions={ specActions }
path={ path }
method={ method }/>
}
</div>
{this.state.executeInProgress ? <div className="loading-container"><div className="loading"></div></div> : null}
{ !responses ? null :
<Responses
responses={ responses }
request={ request }
tryItOutResponse={ response }
getComponent={ getComponent }
specSelectors={ specSelectors }
specActions={ specActions }
produces={ produces }
producesValue={ operation.get("produces_value") }
pathMethod={ [path, method] }
fn={fn} />
}
</div>
</Collapse>
</div>
)
}
}
import React, { PropTypes } from "react"
import {presets} from "react-motion"
export default class Operations extends React.Component {
static propTypes = {
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
layoutSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
authActions: PropTypes.object.isRequired,
authSelectors: PropTypes.object.isRequired,
};
static defaultProps = {
};
render() {
let {
specSelectors,
specActions,
getComponent,
layoutSelectors,
layoutActions,
authActions,
authSelectors,
fn
} = this.props
let taggedOps = specSelectors.taggedOperations()
const Operation = getComponent("operation")
const Collapse = getComponent("Collapse")
const Schemes = getComponent("schemes")
let showSummary = layoutSelectors.showSummary()
return (
<div>
{
taggedOps.map( (tagObj, tag) => {
let operations = tagObj.get("operations")
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
let isShownKey = ["operations-tag", tag]
let showTag = layoutSelectors.isShown(isShownKey, true)
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>
{ !tagDescription ? null :
<small onClick={() => layoutActions.show(isShownKey, !showTag)} >
{ tagDescription }
</small>
}
<button className="expand-methods" title="Expand all methods">
<svg className="expand" width="20" height="20">
<use xlinkHref="#expand" />
</svg>
</button>
<button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}>
<svg className="arrow" width="20" height="20">
<use xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
</svg>
</button>
</h4>
<Collapse isOpened={showTag}>
{
operations.map( op => {
const isShownKey = ["operations", op.get("id"), tag]
const path = op.get("path", "")
const method = op.get("method", "")
const jumpToKey = `paths.${path}.${method}`
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
const response = specSelectors.responseFor(op.get("path"), op.get("method"))
const request = specSelectors.requestFor(op.get("path"), op.get("method"))
return <Operation
{...op.toObject()}
isShownKey={isShownKey}
jumpToKey={jumpToKey}
showSummary={showSummary}
key={isShownKey}
response={ response }
request={ request }
allowTryItOut={allowTryItOut}
specActions={ specActions }
specSelectors={ specSelectors }
layoutActions={ layoutActions }
layoutSelectors={ layoutSelectors }
authActions={ authActions }
authSelectors={ authSelectors }
getComponent={ getComponent }
fn={fn}
/>
}).toArray()
}
</Collapse>
</div>
)
}).toArray()
}
{ taggedOps.size < 1 ? <h3> No operations defined in spec! </h3> : null }
</div>
)
}
}
Operations.propTypes = {
layoutActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
fn: PropTypes.object.isRequired
}
import React, { PropTypes } from "react"
import { Link } from "core/components/layout-utils"
export default class Overview extends React.Component {
constructor(...args) {
super(...args)
this.setTagShown = this._setTagShown.bind(this)
}
_setTagShown(showTagId, shown) {
this.props.layoutActions.show(showTagId, shown)
}
showOp(key, shown) {
let { layoutActions } = this.props
layoutActions.show(key, shown)
}
render() {
let { specSelectors, layoutSelectors, layoutActions, getComponent } = this.props
let taggedOps = specSelectors.taggedOperations()
const Collapse = getComponent("Collapse")
return (
<div>
<h4 className="overview-title">Overview</h4>
{
taggedOps.map( (tagObj, tag) => {
let operations = tagObj.get("operations")
let tagDetails = tagObj.get("tagDetails")
let showTagId = ["overview-tags", tag]
let showTag = layoutSelectors.isShown(showTagId, true)
let toggleShow = ()=> layoutActions.show(showTagId, !showTag)
return (
<div key={"overview-"+tag}>
<h4 onClick={toggleShow} className="link overview-tag"> {showTag ? "-" : "+"}{tag}</h4>
<Collapse isOpened={showTag} animated>
{
operations.map( op => {
let { path, method, operation, id } = op.toObject() // toObject is shallow
let showOpIdPrefix = "operations"
let showOpId = id
let shown = layoutSelectors.isShown([showOpIdPrefix, showOpId])
return <OperationLink key={id}
path={path}
method={method}
id={path + "-" + method}
shown={shown}
showOpId={showOpId}
showOpIdPrefix={showOpIdPrefix}
href={`#operation-${showOpId}`}
onClick={layoutActions.show} />
}).toArray()
}
</Collapse>
</div>
)
}).toArray()
}
{ taggedOps.size < 1 && <h3> No operations defined in spec! </h3> }
</div>
)
}
}
Overview.propTypes = {
layoutSelectors: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
layoutActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
export class OperationLink extends React.Component {
constructor(props) {
super(props)
this.onClick = this._onClick.bind(this)
}
_onClick() {
let { showOpId, showOpIdPrefix, onClick, shown } = this.props
onClick([showOpIdPrefix, showOpId], !shown)
}
render() {
let { id, method, shown, href } = this.props
return (
<Link href={ href } style={{fontWeight: shown ? "bold" : "normal"}} onClick={this.onClick} className="block opblock-link">
<div>
<small className={`bold-label-${method}`}>{method.toUpperCase()}</small>
<span className="bold-label" >{id}</span>
</div>
</Link>
)
}
}
OperationLink.propTypes = {
href: PropTypes.string,
onClick: PropTypes.func,
id: PropTypes.string.isRequired,
method: PropTypes.string.isRequired,
shown: PropTypes.bool.isRequired,
showOpId: PropTypes.string.isRequired,
showOpIdPrefix: PropTypes.string.isRequired
}
import React, { Component, PropTypes } from "react"
import shallowCompare from "react-addons-shallow-compare"
import { Set, fromJS, List } from "immutable"
import { getSampleSchema } from "core/utils"
const NOOP = Function.prototype
export default class ParamBody extends Component {
static propTypes = {
param: PropTypes.object,
onChange: PropTypes.func,
onChangeConsumes: PropTypes.func,
consumes: PropTypes.object,
consumesValue: PropTypes.string,
fn: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
isExecute: PropTypes.bool,
specSelectors: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired
};
static defaultProp = {
consumes: fromJS(["application/json"]),
param: fromJS({}),
onChange: NOOP,
onChangeConsumes: NOOP,
};
constructor(props, context) {
super(props, context)
this.state = {
isEditBox: false,
value: ""
}
}
componentDidMount() {
this.updateValues.call(this, this.props)
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
componentWillReceiveProps(nextProps) {
this.updateValues.call(this, nextProps)
}
updateValues = (props) => {
let { specSelectors, pathMethod, param, isExecute, consumesValue="", onChangeConsumes } = props
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : {}
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})
} else {
if (isXml) {
this.onChange(this.sample("xml"), {isXml: isXml, isEditBox: isExecute})
} else {
this.onChange(this.sample(), {isEditBox: isExecute})
}
}
}
sample = (xml) => {
let { param, fn:{inferSchema} } = this.props
let schema = inferSchema(param.toJS())
return getSampleSchema(schema, xml)
}
onChange = (value, { isEditBox, isXml }) => {
this.setState({value, isEditBox})
this._onChange(value, isXml)
}
_onChange = (val, isXml) => { (this.props.onChange || NOOP)(this.props.param, val, isXml) }
handleOnChange = e => {
let {consumesValue} = this.props
this.onChange(e.target.value.trim(), {isXml: /xml/i.test(consumesValue)})
}
toggleIsEditBox = () => this.setState( state => ({isEditBox: !state.isEditBox}))
render() {
let {
onChangeConsumes,
param,
isExecute,
specSelectors,
pathMethod,
getComponent,
} = this.props
const Button = getComponent("Button")
const TextArea = getComponent("TextArea")
const HighlightCode = getComponent("highlightCode")
const ContentType = getComponent("contentType")
// for domains where specSelectors not passed
let parameter = specSelectors ? specSelectors.getParameter(pathMethod, param.get("name")) : param
let errors = parameter.get("errors", List())
let consumesValue = specSelectors.contentTypeValues(pathMethod).get("requestContentType")
let consumes = this.props.consumes && this.props.consumes.size ? this.props.consumes : ParamBody.defaultProp.consumes
let { value, isEditBox } = this.state
return (
<div className="body-param">
{
isEditBox && isExecute
? <TextArea className={ "body-param__text" + ( errors.count() ? " invalid" : "")} value={value} onChange={ this.handleOnChange }/>
: (value && <HighlightCode className="body-param__example"
value={ value }/>)
}
<div className="body-param-options">
{
!isExecute ? null
: <div className="body-param-edit">
<Button className={isEditBox ? "btn cancel body-param__example-edit" : "btn edit body-param__example-edit"}
onClick={this.toggleIsEditBox}>{ isEditBox ? "Cancel" : "Edit"}
</Button>
</div>
}
<label htmlFor="">
<span>Parameter content type</span>
<ContentType value={ consumesValue } contentTypes={ consumes } onChange={onChangeConsumes} className="body-param-content-type" />
</label>
</div>
</div>
)
}
}
import React, { Component, PropTypes } from "react"
import win from "core/window"
export default class ParameterRow extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
param: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
fn: PropTypes.object.isRequired,
isExecute: PropTypes.bool,
onChangeConsumes: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired
}
constructor(props, context) {
super(props, context)
let { specSelectors, pathMethod, param } = props
let defaultValue = param.get("default")
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
let value = parameter ? parameter.get("value") : ""
if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
}
}
componentWillReceiveProps(props) {
let { specSelectors, pathMethod, param } = props
let defaultValue = param.get("default")
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
let value = parameter ? parameter.get("value") : ""
if ( defaultValue !== undefined && value === undefined ) {
this.onChangeWrapper(defaultValue)
}
}
onChangeWrapper = (value) => {
let { onChange, param } = this.props
return onChange(param, value)
}
render() {
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
// const onChangeWrapper = (value) => onChange(param, value)
const JsonSchemaForm = getComponent("JsonSchemaForm")
const ParamBody = getComponent("ParamBody")
let inType = param.get("in")
let bodyParam = inType !== "body" ? null
: <ParamBody getComponent={getComponent}
fn={fn}
param={param}
consumes={ specSelectors.operationConsumes(pathMethod) }
consumesValue={ specSelectors.contentTypeValues(pathMethod).get("requestContentType") }
onChange={onChange}
onChangeConsumes={onChangeConsumes}
isExecute={ isExecute }
specSelectors={ specSelectors }
pathMethod={ pathMethod }
/>
const ModelExample = getComponent("modelExample")
const Markdown = getComponent("Markdown")
let schema = param.get("schema")
let isFormData = inType === "formData"
let isFormDataSupported = "FormData" in win
let required = param.get("required")
let itemType = param.getIn(["items", "type"])
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
let value = parameter ? parameter.get("value") : ""
return (
<tr>
<td className="col parameters-col_name">
<div className={required ? "parameter__name required" : "parameter__name"}>
{ param.get("name") }
{ !required ? null : <span style={{color: "red"}}>&nbsp;*</span> }
</div>
<div className="parаmeter__type">{ param.get("type") } { itemType && `[${itemType}]` }</div>
<div className="parameter__in">({ param.get("in") })</div>
</td>
<td className="col parameters-col_description">
<Markdown options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}}
source={ param.get("description") }/>
{(isFormData && !isFormDataSupported) && <div>Error: your browser does not support FormData</div>}
{ bodyParam || !isExecute ? null
: <JsonSchemaForm fn={fn}
getComponent={getComponent}
value={ value }
required={ required }
description={param.get("description") ? `${param.get("name")} - ${param.get("description")}` : `${param.get("name")}`}
onChange={ this.onChangeWrapper }
schema={ param }/>
}
{
bodyParam && schema ? <ModelExample getComponent={ getComponent }
isExecute={ isExecute }
specSelectors={ specSelectors }
schema={ schema }
example={ bodyParam }/>
: null
}
</td>
</tr>
)
}
}
import React, { Component, PropTypes } from "react"
import ImPropTypes from "react-immutable-proptypes"
import Im, { fromJS } from "immutable"
// More readable, just iterate over maps, only
const eachMap = (iterable, fn) => iterable.valueSeq().filter(Im.Map.isMap).map(fn)
export default class Parameters extends Component {
static propTypes = {
parameters: ImPropTypes.list.isRequired,
specActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired,
tryItOutEnabled: PropTypes.bool,
allowTryItOut: PropTypes.bool,
onTryoutClick: PropTypes.func,
onCancelClick: PropTypes.func,
onChangeKey: PropTypes.array,
pathMethod: PropTypes.array.isRequired
}
static defaultProps = {
onTryoutClick: Function.prototype,
onCancelClick: Function.prototype,
tryItOutEnabled: false,
allowTryItOut: true,
onChangeKey: [],
}
onChange = ( param, value, isXml ) => {
let {
specActions: { changeParam },
onChangeKey,
} = this.props
changeParam( onChangeKey, param.get("name"), value, isXml)
}
onChangeConsumesWrapper = ( val ) => {
let {
specActions: { changeConsumesValue },
onChangeKey
} = this.props
changeConsumesValue(onChangeKey, val)
}
render(){
let {
onTryoutClick,
onCancelClick,
parameters,
allowTryItOut,
tryItOutEnabled,
fn,
getComponent,
specSelectors,
pathMethod
} = this.props
const ParameterRow = getComponent("parameterRow")
const TryItOutButton = getComponent("TryItOutButton")
const isExecute = tryItOutEnabled && allowTryItOut
return (
<div className="opblock-section">
<div className="opblock-section-header">
<h4 className="opblock-title">Parameters</h4>
{ allowTryItOut ? (
<TryItOutButton enabled={ tryItOutEnabled } onCancelClick={ onCancelClick } onTryoutClick={ onTryoutClick } />
) : null }
</div>
{ !parameters.count() ? <div className="opblock-description-wrapper"><p>No parameters</p></div> :
<div className="table-container">
<table className="parameters">
<thead>
<tr>
<th className="col col_header parameters-col_name">Name</th>
<th className="col col_header parameters-col_description">Description</th>
</tr>
</thead>
<tbody>
{
eachMap(parameters, (parameter, k) => (
<ParameterRow fn={ fn }
getComponent={ getComponent }
param={ parameter }
key={ parameter.get( "name" ) }
onChange={ this.onChange }
onChangeConsumes={this.onChangeConsumesWrapper}
specSelectors={ specSelectors }
pathMethod={ pathMethod }
isExecute={ isExecute }/>
)).toArray()
}
</tbody>
</table>
</div>
}
</div>
)
}
}
import React, { PropTypes } from "react"
import { formatXml } from "core/utils"
import lowerCase from "lodash/lowerCase"
export default class ResponseBody extends React.Component {
static propTypes = {
content: PropTypes.any.isRequired,
contentType: PropTypes.string.isRequired,
getComponent: PropTypes.func.isRequired,
headers: PropTypes.object,
url: PropTypes.string
}
render() {
let { content, contentType, url, headers={}, getComponent } = this.props
const HighlightCode = getComponent("highlightCode")
let body, bodyEl
url = url || ""
// JSON
if (/json/i.test(contentType)) {
try {
body = JSON.stringify(JSON.parse(content), null, " ")
} catch (error) {
body = "can't parse JSON. Raw result:\n\n" + content
}
bodyEl = <HighlightCode value={ body } />
// XML
} else if (/xml/i.test(contentType)) {
body = formatXml(content)
bodyEl = <HighlightCode value={ body } />
// HTML or Plain Text
} else if (lowerCase(contentType) === "text/html" || /text\/plain/.test(contentType)) {
bodyEl = <HighlightCode value={ content } />
// Image
} else if (/^image\//i.test(contentType)) {
bodyEl = <img src={ url } />
// Audio
} else if (/^audio\//i.test(contentType)) {
bodyEl = <pre><audio controls><source src={ url } type={ contentType } /></audio></pre>
// Download
} else if (
/^application\/octet-stream/i.test(contentType) ||
headers["Content-Disposition"] && (/attachment/i).test(headers["Content-Disposition"]) ||
headers["content-disposition"] && (/attachment/i).test(headers["content-disposition"]) ||
headers["Content-Description"] && (/File Transfer/i).test(headers["Content-Description"]) ||
headers["content-description"] && (/File Transfer/i).test(headers["content-description"])) {
let contentLength = headers["content-length"] || headers["Content-Length"]
if ( !(+contentLength) ) return null
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
if (!isSafari && "Blob" in window) {
let type = contentType || "text/html"
let blob = (content instanceof Blob) ? content : new Blob([content], {type: type})
let href = window.URL.createObjectURL(blob)
let fileName = url.substr(url.lastIndexOf("/") + 1)
let download = [type, fileName, href].join(":")
// Use filename from response header
let disposition = headers["content-disposition"] || headers["Content-Disposition"]
if (typeof disposition !== "undefined") {
let responseFilename = /filename=([^;]*);?/i.exec(disposition)
if (responseFilename !== null && responseFilename.length > 1) {
download = responseFilename[1]
}
}
bodyEl = <div><a href={ href } download={ download }>{ "Download file" }</a></div>
} else {
bodyEl = <pre>Download headers detected but your browser does not support downloading binary via XHR (Blob).</pre>
}
// Anything else (CORS)
} else if (typeof content === "string") {
bodyEl = <HighlightCode value={ content } />
} else {
bodyEl = <div>Unknown response type</div>
}
return ( !bodyEl ? null : <div>
<h5>Response body</h5>
{ bodyEl }
</div>
)
}
}
import React, { PropTypes } from "react"
import { fromJS } from 'immutable'
import { getSampleSchema } from "core/utils"
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
if ( examples && examples.size ) {
return examples.entrySeq().map( ([ key, example ]) => {
return (<div key={ key }>
<h5>{ key }</h5>
<HighlightCode className="example" value={ example } />
</div>)
}).toArray()
}
if ( sampleResponse ) { return <div>
<HighlightCode className="example" value={ sampleResponse } />
</div>
}
return null
}
export default class Response extends React.Component {
static propTypes = {
code: PropTypes.string.isRequired,
response: PropTypes.object,
className: PropTypes.string,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
fn: PropTypes.object.isRequired,
contentType: PropTypes.string
}
static defaultProps = {
response: fromJS({}),
};
render() {
let {
code,
response,
className,
fn,
getComponent,
specSelectors,
contentType
} = this.props
let { inferSchema } = fn
let schema = inferSchema(response.toJS())
let headers = response.get("headers")
let examples = response.get("examples")
const Headers = getComponent("headers")
const HighlightCode = getComponent("highlightCode")
const ModelExample = getComponent("modelExample")
const Markdown = getComponent( "Markdown" )
let sampleResponse = schema ? getSampleSchema(schema, contentType, { includeReadOnly: true }) : null
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
return (
<tr className={ "response " + ( className || "") }>
<td className="col response-col_status">
{ code }
</td>
<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" ) } />
</div>
{ example ? (
<ModelExample
getComponent={ getComponent }
specSelectors={ specSelectors }
schema={ fromJS(schema) }
example={ example }/>
) : null}
{ headers ? (
<Headers headers={ headers }/>
) : null}
</td>
</tr>
)
}
}
import React, { PropTypes } from "react"
import { fromJS } from "immutable"
import { defaultStatusCode } from "core/utils"
export default class Responses extends React.Component {
static propTypes = {
request: PropTypes.object,
tryItOutResponse: PropTypes.object,
responses: PropTypes.object.isRequired,
produces: PropTypes.object,
producesValue: PropTypes.any,
getComponent: PropTypes.func.isRequired,
specSelectors: PropTypes.object.isRequired,
specActions: PropTypes.object.isRequired,
pathMethod: PropTypes.array.isRequired,
fn: PropTypes.object.isRequired
}
static defaultProps = {
request: null,
tryItOutResponse: null,
produces: fromJS(["application/json"])
}
onChangeProducesWrapper = ( val ) => this.props.specActions.changeProducesValue(this.props.pathMethod, val)
render() {
let { responses, request, tryItOutResponse, getComponent, specSelectors, fn, producesValue } = this.props
let defaultCode = defaultStatusCode( responses )
const ContentType = getComponent( "contentType" )
const LiveResponse = getComponent( "liveResponse" )
const Response = getComponent( "response" )
let produces = this.props.produces && this.props.produces.size ? this.props.produces : Responses.defaultProps.produces
return (
<div className="responses-wrapper">
<div className="opblock-section-header">
<h4>Responses</h4>
<label>
<span>Response content type</span>
<ContentType value={producesValue}
onChange={this.onChangeProducesWrapper}
contentTypes={produces}
className="execute-content-type"/>
</label>
</div>
<div className="responses-inner">
{
!tryItOutResponse ? null
: <div>
<LiveResponse request={ request }
response={ tryItOutResponse }
getComponent={ getComponent } />
<h4>Responses</h4>
</div>
}
<table className="responses-table">
<thead>
<tr className="responses-header">
<td className="col col_header response-col_status">Code</td>
<td className="col col_header response-col_description">Description</td>
</tr>
</thead>
<tbody>
{
responses.entrySeq().map( ([code, response]) => {
let className = tryItOutResponse && tryItOutResponse.get("status") == code ? "response_current" : ""
return (
<Response key={ code }
isDefault={defaultCode === code}
fn={fn}
className={ className }
code={ code }
response={ response }
specSelectors={ specSelectors }
contentType={ producesValue }
getComponent={ getComponent }/>
)
}).toArray()
}
</tbody>
</table>
</div>
</div>
)
}
}
import React, { PropTypes } from "react"
export default class Schemes extends React.Component {
static propTypes = {
specActions: PropTypes.object.isRequired,
schemes: PropTypes.object.isRequired,
path: PropTypes.string,
method: PropTypes.string
}
componentWillMount() {
let { schemes } = this.props
//fire 'change' event to set default 'value' of select
this.setScheme(schemes.first())
}
onChange =( e ) => {
let { path, method, specActions } = this.props
this.setScheme( e.target.value )
}
setScheme =( value ) => {
let { path, method, specActions } = this.props
specActions.setScheme( value, path, method )
}
render() {
let { schemes } = this.props
return (
<label htmlFor="schemes">
<span>Schemes</span>
<select onChange={ this.onChange }>
{ schemes.valueSeq().map(
( scheme ) => <option value={ scheme } key={ scheme }>{ scheme }</option>
).toArray()}
</select>
</label>
)
}
}
import React, { PropTypes } from "react"
export default class TryItOutButton extends React.Component {
static propTypes = {
onTryoutClick: PropTypes.func,
enabled: PropTypes.bool, // Try it out is enabled, ie: the user has access to the form
};
static defaultProps = {
onTryoutClick: Function.prototype,
enabled: false,
};
render() {
const { onTryoutClick, onCancelClick, enabled } = this.props
return (
<div className="try-out">
{
enabled ? <button className="btn try-out__btn cancel" onClick={ onTryoutClick }>Cancel</button>
: <button className="btn try-out__btn" onClick={ onCancelClick }>Try it out </button>
}
</div>
)
}
}
export default function curl( request ){
let curlified = []
let type = ""
let headers = request.get("headers")
curlified.push( "curl" )
curlified.push( "-X", request.get("method") )
curlified.push( request.get("url") )
if ( headers && headers.size ) {
for( let p of request.get("headers").entries() ){
let [ h,v ] = p
type = v
curlified.push( "-H " )
curlified.push( `"${h}: ${v}"` )
}
}
if ( request.get("body") ){
if(type === "multipart/form-data" && request.get("method") === "POST") {
let formDataBody = request.get("body").split("&")
for(var data in formDataBody) {
curlified.push( "-F" )
curlified.push(formDataBody[data])
}
} else {
curlified.push( "-d" )
curlified.push( JSON.stringify( request.get("body") ).replace(/\\n/g, "") )
}
}
return curlified.join( " " )
}
import deepExtend from "deep-extend"
import System from "core/system"
import ApisPreset from "core/presets/apis"
import * as AllPlugins from "core/plugins/all"
import { filterConfigs } from "plugins/configs"
module.exports = function SwaggerUI(opts) {
const defaults = {
// Some general settings, that we floated to the top
dom_id: null,
spec: {},
url: "",
layout: "Layout",
configs: {
validatorUrl: "https://online.swagger.io/validator"
},
// 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.
presets: [
],
// Plugins; ( loaded after presets )
plugins: [
],
// Inline Plugin
fn: { },
components: { },
state: { },
// Override some core configs... at your own risk
store: { },
}
const config = deepExtend({}, defaults, opts)
const storeConfigs = deepExtend({}, config.store, {
system: {
configs: config.configs
},
plugins: config.presets,
state: {
layout: {
layout: config.layout
},
spec: {
spec: "",
url: config.url
}
}
})
let inlinePlugin = ()=> {
return {
fn: config.fn,
components: config.components,
state: config.state,
}
}
var store = new System(storeConfigs)
store.register([config.plugins, inlinePlugin])
var system = store.getSystem()
const downloadSpec = (configs) => {
if(typeof config !== "object") {
return system
}
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
let mergedConfig = deepExtend({}, config, configs, localConfig)
store.setConfigs(filterConfigs(mergedConfig))
if(typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
system.specActions.updateUrl("")
system.specActions.updateLoadingStatus("success");
system.specActions.updateSpec(JSON.stringify(mergedConfig.spec))
} else if(mergedConfig.url) {
system.specActions.updateUrl(mergedConfig.url)
system.specActions.download(mergedConfig.url)
}
if(mergedConfig.dom_id)
system.render(mergedConfig.dom_id, "App")
return system
}
if (system.specActions.getConfigByUrl && !system.specActions.getConfigByUrl(downloadSpec)) {
return downloadSpec(config)
}
if (system.specActions.download && config.url) {
system.specActions.download(config.url)
}
if(config.spec && typeof config.spec === "string")
system.specActions.updateSpec(config.spec)
if(config.dom_id) {
system.render(config.dom_id, "App")
} else {
console.error("Skipped rendering: no `dom_id` was specified")
}
return system
}
// Add presets
module.exports.presets = {
apis: ApisPreset,
}
// All Plugins
module.exports.plugins = AllPlugins
import React, { PropTypes, Component } from "react"
import { arrayify } from "core/utils"
import shallowCompare from "react-addons-shallow-compare"
import { List, fromJS } from "immutable"
import assign from "object-assign"
//import "less/json-schema-form"
const noop = ()=> {}
const JsonSchemaPropShape = {
getComponent: PropTypes.func.isRequired,
value: PropTypes.any,
onChange: PropTypes.func,
keyName: PropTypes.any,
fn: PropTypes.object.isRequired,
schema: PropTypes.object,
required: PropTypes.bool,
description: PropTypes.any
}
const JsonSchemaDefaultProps = {
value: "",
onChange: noop,
schema: {},
keyName: "",
required: false
}
export class JsonSchemaForm extends Component {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps
render() {
let { schema, value, onChange, getComponent, fn } = this.props
if(schema.toJS)
schema = schema.toJS()
let { type, format="" } = schema
let Comp = getComponent(`JsonSchema_${type}_${format}`) || getComponent(`JsonSchema_${type}`) || getComponent("JsonSchema_string")
return <Comp { ...this.props } fn={fn} getComponent={getComponent} value={value} onChange={onChange} schema={schema}/>
}
}
export class JsonSchema_string extends Component {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps
onChange = (e) => {
const value = this.props.schema["type"] === "file" ? e.target.files[0] : e.target.value
this.props.onChange(value, this.props.keyName)
}
onEnumChange = (val) => this.props.onChange(val)
render() {
let { getComponent, value, schema, fn, required, description } = this.props
let enumValue = schema["enum"]
let errors = schema.errors || []
if ( enumValue ) {
const Select = getComponent("Select")
return (<Select allowedValues={ enumValue }
value={ value }
allowEmptyValue={ !required }
onChange={ this.onEnumChange }/>)
}
const isDisabled = schema["in"] === "formData" && !("FormData" in window)
const Input = getComponent("Input")
if (schema["type"] === "file") {
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}/>
}
}
}
export class JsonSchema_array extends Component {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps
constructor(props, context) {
super(props, context)
this.state = {value: props.value}
}
componentWillReceiveProps(props) {
if(props.value !== this.state.value)
this.setState({value: props.value})
}
shouldComponentUpdate(props, state) {
return shallowCompare(this, props, state)
}
onChange = () => this.props.onChange(this.state.value)
onItemChange = (itemVal, i) => {
this.setState(state => ({
value: state.value.set(i, itemVal)
}), this.onChange)
}
removeItem = (i) => {
this.setState(state => ({
value: state.value.remove(i)
}), this.onChange)
}
addItem = () => {
this.setState(state => {
state.value = state.value || List()
return {
value: state.value.push("")
}
}, this.onChange)
}
onEnumChange = (value) => {
this.setState(state => ({
value: value
}), this.onChange)
}
render() {
let { getComponent, onChange, required, schema, fn } = this.props
let itemSchema = fn.inferSchema(schema.items)
const JsonSchemaForm = getComponent("JsonSchemaForm")
const Button = getComponent("Button")
let enumValue = itemSchema["enum"]
let value = this.state.value
if ( enumValue ) {
const Select = getComponent("Select")
return (<Select multiple={ true }
value={ value }
allowedValues={ enumValue }
allowEmptyValue={ !required }
onChange={ this.onEnumChange }/>)
}
let errors = schema.errors || []
return (
<div>
{ !value || value.count() < 1 ?
(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 ]
}
return (
<div key={i} className="json-schema-form-item">
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
<Button className="json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
</div>
)
}).toArray()
}
<Button className="json-schema-form-item-add" onClick={this.addItem}> Add item </Button>
</div>
)
}
}
export class JsonSchema_boolean extends Component {
static propTypes = JsonSchemaPropShape
static defaultProps = JsonSchemaDefaultProps
onEnumChange = (val) => this.props.onChange(val)
render() {
let { getComponent, required, value } = this.props
const Select = getComponent("Select")
return (<Select value={ String(value) }
allowedValues={ fromJS(["true", "false"]) }
allowEmptyValue={ !required }
onChange={ this.onEnumChange }/>)
}
}
import win from "core/window"
export default function authorize ( auth, authActions, errActions, configs ) {
let { schema, scopes, name, clientId } = auth
let redirectUrl = configs.oauth2RedirectUrl
let scopeSeparator = " "
let state = name
let flow = schema.get("flow")
let url
if (flow === "password") {
authActions.authorizePassword(auth)
return
}
// todo move to parser
if ( !redirectUrl ) {
errActions.newAuthErr( {
authId: name,
source: "validation",
level: "error",
message: "oauth2RedirectUri configuration is not passed. Oauth2 authorization cannot be performed."
})
return
}
if (flow === "implicit" || flow === "accessCode") {
url = schema.get("authorizationUrl") + "?response_type=" + (flow === "implicit" ? "token" : "code")
}
url += "&redirect_uri=" + encodeURIComponent(redirectUrl)
+ "&scope=" + encodeURIComponent(scopes.join(scopeSeparator))
+ "&state=" + encodeURIComponent(state)
+ "&client_id=" + encodeURIComponent(clientId)
// pass action authorizeOauth2 and authentication data through window
// to authorize with oauth2
win.swaggerUIRedirectOauth2 = {
auth: auth,
state: state,
callback: authActions.preAuthorizeOauth2,
errCb: errActions.newAuthErr
}
win.open(url)
}
import get from "lodash/get"
export function transformPathToArray(property, jsSpec) {
if(property.slice(0,9) === "instance.") {
var str = property.slice(9)
} else { // eslint-disable-next-line no-redeclare
var str = property
}
var pathArr = []
str
.split(".")
.map(item => {
// "key[0]" becomes ["key", "0"]
if(item.includes("[")) {
let index = parseInt(item.match(/\[(.*)\]/)[1])
let keyName = item.slice(0, item.indexOf("["))
return [keyName, index.toString()]
} else {
return item
}
})
.reduce(function(a, b) {
// flatten!
return a.concat(b)
}, [])
.concat([""]) // add an empty item into the array, so we don't get stuck with something in our buffer below
.reduce((buffer, curr, i, arr) => {
let obj = pathArr.length ? get(jsSpec, pathArr) : jsSpec
if(get(obj, makeAccessArray(buffer, curr))) {
if(buffer.length) {
pathArr.push(buffer)
}
if(curr.length) {
pathArr.push(curr)
}
return ""
} else {
// attach key to buffer
return `${buffer}${buffer.length ? "." : ""}${curr}`
}
}, "")
if(typeof get(jsSpec, pathArr) !== "undefined") {
return pathArr
} else {
// if our path is not correct (there is no value at the path),
// return null
return null
}
}
function makeAccessArray(buffer, curr) {
let arr = []
if(buffer.length) {
arr.push(buffer)
}
if(curr.length) {
arr.push(curr)
}
return arr
}
import { pascalCaseFilename } from "core/utils"
const request = require.context(".", true, /\.jsx?$/)
request.keys().forEach( function( key ){
if( key === "./index.js" ) {
return
}
// if( key.slice(2).indexOf("/") > -1) {
// // skip files in subdirs
// return
// }
let mod = request(key)
module.exports[pascalCaseFilename(key)] = mod.default ? mod.default : mod
})
import React, { PropTypes } from "react"
export default function (system) {
return {
components: {
NoHostWarning,
},
statePlugins: {
spec: {
selectors: {
allowTryItOutFor,
}
}
}
}
}
// This is a quick style. How do we improve this?
const style = {
backgroundColor: "#e7f0f7",
padding: "1rem",
borderRadius: "3px",
}
function NoHostWarning() {
return (
<div style={style}>Note: The interactive forms are disabled, as no `host` property was found in the specification. Please see: <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object" target="_blank">OAI 2.0/#swagger-object</a></div>
)
}
// Only allow if, there is a host field
function allowTryItOutFor(state) {
return ({specSelectors}) => {
return specSelectors.hasHost(state)
}
}
import YAML from "yaml-js"
import isArray from "lodash/isArray"
import lodashFind from "lodash/find"
import { memoize } from "core/utils"
let cachedCompose = memoize(YAML.compose) // TODO: build a custom cache based on content
var MAP_TAG = "tag:yaml.org,2002:map"
var SEQ_TAG = "tag:yaml.org,2002:seq"
export function getLineNumberForPath(yaml, path) {
// Type check
if (typeof yaml !== "string") {
throw new TypeError("yaml should be a string")
}
if (!isArray(path)) {
throw new TypeError("path should be an array of strings")
}
var i = 0
let ast = cachedCompose(yaml)
// simply walks the tree using current path recursively to the point that
// path is empty
return find(ast, path)
function find(current, path, last) {
if(!current) {
// something has gone quite wrong
// return the last start_mark as a best-effort
if(last && last.start_mark)
return last.start_mark.line
return 0
}
if (path.length && current.tag === MAP_TAG) {
for (i = 0; i < current.value.length; i++) {
var pair = current.value[i]
var key = pair[0]
var value = pair[1]
if (key.value === path[0]) {
return find(value, path.slice(1), current)
}
if (key.value === path[0].replace(/\[.*/, "")) {
// access the array at the index in the path (example: grab the 2 in "tags[2]")
var index = parseInt(path[0].match(/\[(.*)\]/)[1])
if(value.value.length === 1 && index !== 0 && !!index) {
var nextVal = lodashFind(value.value[0], { value: index.toString() })
} else { // eslint-disable-next-line no-redeclare
var nextVal = value.value[index]
}
return find(nextVal, path.slice(1), value.value)
}
}
}
if (path.length && current.tag === SEQ_TAG) {
var item = current.value[path[0]]
if (item && item.tag) {
return find(item, path.slice(1), current.value)
}
}
if (current.tag === MAP_TAG && !Array.isArray(last)) {
return current.start_mark.line
} else {
return current.start_mark.line + 1
}
}
}
/**
* Get a position object with given
* @param {string} yaml
* YAML or JSON string
* @param {array} path
* an array of stings that constructs a
* JSON Path similiar to JSON Pointers(RFC 6901). The difference is, each
* component of path is an item of the array intead of beinf seperated with
* slash(/) in a string
*/
export function positionRangeForPath(yaml, path) {
// Type check
if (typeof yaml !== "string") {
throw new TypeError("yaml should be a string")
}
if (!isArray(path)) {
throw new TypeError("path should be an array of strings")
}
var invalidRange = {
start: {line: -1, column: -1},
end: {line: -1, column: -1}
}
var i = 0
let ast = cachedCompose(yaml)
// simply walks the tree using current path recursively to the point that
// path is empty.
return find(ast)
function find(current) {
if (current.tag === MAP_TAG) {
for (i = 0; i < current.value.length; i++) {
var pair = current.value[i]
var key = pair[0]
var value = pair[1]
if (key.value === path[0]) {
path.shift()
return find(value)
}
}
}
if (current.tag === SEQ_TAG) {
var item = current.value[path[0]]
if (item && item.tag) {
path.shift()
return find(item)
}
}
// if path is still not empty we were not able to find the node
if (path.length) {
return invalidRange
}
return {
/* jshint camelcase: false */
start: {
line: current.start_mark.line,
column: current.start_mark.column
},
end: {
line: current.end_mark.line,
column: current.end_mark.column
}
}
}
}
/**
* Get a JSON Path for position object in the spec
* @param {string} yaml
* YAML or JSON string
* @param {object} position
* position in the YAML or JSON string with `line` and `column` properties.
* `line` and `column` number are zero indexed
*/
export function pathForPosition(yaml, position) {
// Type check
if (typeof yaml !== "string") {
throw new TypeError("yaml should be a string")
}
if (typeof position !== "object" || typeof position.line !== "number" ||
typeof position.column !== "number") {
throw new TypeError("position should be an object with line and column" +
" properties")
}
try {
var ast = cachedCompose(yaml)
} catch (e) {
console.error("Error composing AST", e)
console.error(`Problem area:\n`, yaml.split("\n").slice(position.line - 5, position.line + 5).join("\n"))
return null
}
var path = []
return find(ast)
/**
* recursive find function that finds the node matching the position
* @param {object} current - AST object to serach into
*/
function find(current) {
// algorythm:
// is current a promitive?
// // finish recursion without modifying the path
// is current a hash?
// // find a key or value that position is in their range
// // if key is in range, terminate recursion with exisiting path
// // if a value is in range push the corresponding key to the path
// // andcontinue recursion
// is current an array
// // find the item that position is in it"s range and push the index
// // of the item to the path and continue recursion with that item.
var i = 0
if (!current || [MAP_TAG, SEQ_TAG].indexOf(current.tag) === -1) {
return path
}
if (current.tag === MAP_TAG) {
for (i = 0; i < current.value.length; i++) {
var pair = current.value[i]
var key = pair[0]
var value = pair[1]
if (isInRange(key)) {
return path
} else if (isInRange(value)) {
path.push(key.value)
return find(value)
}
}
}
if (current.tag === SEQ_TAG) {
for (i = 0; i < current.value.length; i++) {
var item = current.value[i]
if (isInRange(item)) {
path.push(i.toString())
return find(item)
}
}
}
return path
/**
* Determines if position is in node"s range
* @param {object} node - AST node
* @return {Boolean} true if position is in node"s range
*/
function isInRange(node) {
/* jshint camelcase: false */
// if node is in a single line
if (node.start_mark.line === node.end_mark.line) {
return (position.line === node.start_mark.line) &&
(node.start_mark.column <= position.column) &&
(node.end_mark.column >= position.column)
}
// if position is in the same line as start_mark
if (position.line === node.start_mark.line) {
return position.column >= node.start_mark.column
}
// if position is in the same line as end_mark
if (position.line === node.end_mark.line) {
return position.column <= node.end_mark.column
}
// if position is between start and end lines return true, otherwise
// return false.
return (node.start_mark.line < position.line) &&
(node.end_mark.line > position.line)
}
}
}
// utility fns
export let pathForPositionAsync = promisifySyncFn(pathForPosition)
export let positionRangeForPathAsync = promisifySyncFn(positionRangeForPath)
export let getLineNumberForPathAsync = promisifySyncFn(getLineNumberForPath)
function promisifySyncFn(fn) {
return function(...args) {
return new Promise(function(resolve, reject) {
resolve(fn(...args))
})
}
}
import * as AST from "./ast"
import JumpToPath from "./jump-to-path"
export default function() {
return {
fn: { AST },
components: { JumpToPath }
}
}
import React from "react"
// Nothing by default- component can be overriden by another plugin.
export default class JumpToPath extends React.Component {
render() {
return null
}
}
import win from "core/window"
import btoa from "btoa"
export const SHOW_AUTH_POPUP = "show_popup"
export const AUTHORIZE = "authorize"
export const LOGOUT = "logout"
export const PRE_AUTHORIZE_OAUTH2 = "pre_authorize_oauth2"
export const AUTHORIZE_OAUTH2 = "authorize_oauth2"
export const VALIDATE = "validate"
export function showDefinitions(payload) {
return {
type: SHOW_AUTH_POPUP,
payload: payload
}
}
export function authorize(payload) {
return {
type: AUTHORIZE,
payload: payload
}
}
export function logout(payload) {
return {
type: LOGOUT,
payload: payload
}
}
export const preAuthorizeOauth2 = (payload) => ( { authActions, errActions } ) => {
let { auth , token, isValid } = payload
let { schema, name } = auth
let flow = schema.get("flow")
// remove oauth2 property from window after redirect from authentication
delete win.swaggerUIRedirectOauth2
if ( flow !== "accessCode" && !isValid ) {
errActions.newAuthErr( {
authId: name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
})
}
if ( token.error ) {
errActions.newAuthErr({
authId: name,
source: "auth",
level: "error",
message: JSON.stringify(token)
})
return
}
authActions.authorizeOauth2({ auth, token })
}
export function authorizeOauth2(payload) {
return {
type: AUTHORIZE_OAUTH2,
payload: payload
}
}
export const authorizePassword = ( auth ) => ( { fn, authActions, errActions } ) => {
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
}
}
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 fn.fetch(req)
.then(( 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(err => { errActions.newAuthErr( err ) })
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
export function transform(errors) {
return errors
.map(err => {
return err.set("message", removeSubstring(err.get("message"), "instance."))
})
}
function removeSubstring(str, substr) {
return str.replace(new RegExp(substr, "g"), "")
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册