mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-09 14:44:51 +03:00
Merge branch 'master-with-console'
This commit is contained in:
commit
64ca4cc29d
21
.github/workflows/unit-tests.yml
vendored
Normal file
21
.github/workflows/unit-tests.yml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: Unit Tests
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 10.x
|
||||||
|
- name: yarn install, build, and test
|
||||||
|
run: |
|
||||||
|
npm install -g yarn
|
||||||
|
yarn install
|
||||||
|
yarn bundle
|
||||||
|
yarn test
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -36,3 +36,6 @@ cli/index.js
|
||||||
stats.json
|
stats.json
|
||||||
/package-lock.json
|
/package-lock.json
|
||||||
/.idea/
|
/.idea/
|
||||||
|
|
||||||
|
# npmrc for local npm
|
||||||
|
.npmrc
|
||||||
|
|
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -1,3 +1,36 @@
|
||||||
|
# [2.0.0-rc.16](https://github.com/Redocly/redoc/compare/v2.0.0-rc.15...v2.0.0-rc.16) (2019-09-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix scrollYOffset when SSR ([d09c1c1](https://github.com/Redocly/redoc/commit/d09c1c1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.0.0-rc.15](https://github.com/Redocly/redoc/compare/v2.0.0-rc.14...v2.0.0-rc.15) (2019-09-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* auth section appears twice ([5aa7784](https://github.com/Redocly/redoc/commit/5aa7784)), closes [#818](https://github.com/Redocly/redoc/issues/818)
|
||||||
|
* clicking on group title breaks first tag ([4649683](https://github.com/Redocly/redoc/commit/4649683)), closes [#1034](https://github.com/Redocly/redoc/issues/1034)
|
||||||
|
* do not crash on empty scopes ([e787d9e](https://github.com/Redocly/redoc/commit/e787d9e)), closes [#1044](https://github.com/Redocly/redoc/issues/1044)
|
||||||
|
* false-positive recursive detection with allOf at the same level ([faa74d6](https://github.com/Redocly/redoc/commit/faa74d6))
|
||||||
|
* fix scrollYOffset when SSR ([21258a5](https://github.com/Redocly/redoc/commit/21258a5))
|
||||||
|
* left menu item before group is not highligted ([67e2a8f](https://github.com/Redocly/redoc/commit/67e2a8f)), closes [#1033](https://github.com/Redocly/redoc/issues/1033)
|
||||||
|
* remove excessive whitespace between md sections on small screens ([e318fb3](https://github.com/Redocly/redoc/commit/e318fb3)), closes [#874](https://github.com/Redocly/redoc/issues/874)
|
||||||
|
* use url-template dependency ([#1008](https://github.com/Redocly/redoc/issues/1008)) ([32a464a](https://github.com/Redocly/redoc/commit/32a464a)), closes [#1007](https://github.com/Redocly/redoc/issues/1007)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **cli:** added support for JSON string value for --options CLI argument ([#1047](https://github.com/Redocly/redoc/issues/1047)) ([2a28130](https://github.com/Redocly/redoc/commit/2a28130)), closes [#797](https://github.com/Redocly/redoc/issues/797)
|
||||||
|
* **cli:** add `disableGoogleFont` parameter to cli ([#1045](https://github.com/Redocly/redoc/issues/1045)) ([aceb343](https://github.com/Redocly/redoc/commit/aceb343))
|
||||||
|
* new option expandDefaultServerVariables ([#1014](https://github.com/Redocly/redoc/issues/1014)) ([0360dce](https://github.com/Redocly/redoc/commit/0360dce))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [2.0.0-rc.14](https://github.com/Redocly/redoc/compare/v2.0.0-rc.13...v2.0.0-rc.14) (2019-08-07)
|
# [2.0.0-rc.14](https://github.com/Redocly/redoc/compare/v2.0.0-rc.13...v2.0.0-rc.14) (2019-08-07)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ For npm:
|
||||||
|
|
||||||
Install peer dependencies required by ReDoc if you don't have them installed already:
|
Install peer dependencies required by ReDoc if you don't have them installed already:
|
||||||
|
|
||||||
npm i react react-dom mobx@^4.2.0 styled-components
|
npm i react react-dom mobx@^4.2.0 styled-components core-js
|
||||||
|
|
||||||
Import `RedocStandalone` component from 'redoc' module:
|
Import `RedocStandalone` component from 'redoc' module:
|
||||||
|
|
||||||
|
@ -246,6 +246,7 @@ You can use all of the following options with standalone version on <redoc> tag
|
||||||
* `onlyRequiredInSamples` - shows only required fields in request samples.
|
* `onlyRequiredInSamples` - shows only required fields in request samples.
|
||||||
* `jsonSampleExpandLevel` - set the default expand level for JSON payload samples (responses and request body). Special value 'all' expands all levels. The default value is `2`.
|
* `jsonSampleExpandLevel` - set the default expand level for JSON payload samples (responses and request body). Special value 'all' expands all levels. The default value is `2`.
|
||||||
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `false`
|
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `false`
|
||||||
|
* `expandDefaultServerVariables` - enable expanding default server variables, default `false`
|
||||||
* `theme` - ReDoc theme. Not documented yet. For details check source code: [theme.ts](https://github.com/Redocly/redoc/blob/master/src/theme.ts)
|
* `theme` - ReDoc theme. Not documented yet. For details check source code: [theme.ts](https://github.com/Redocly/redoc/blob/master/src/theme.ts)
|
||||||
|
|
||||||
## Advanced usage of standalone version
|
## Advanced usage of standalone version
|
||||||
|
|
70
cli/index.ts
70
cli/index.ts
|
@ -25,6 +25,7 @@ interface Options {
|
||||||
cdn?: boolean;
|
cdn?: boolean;
|
||||||
output?: string;
|
output?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
disableGoogleFont?: boolean;
|
||||||
port?: number;
|
port?: number;
|
||||||
templateFileName?: string;
|
templateFileName?: string;
|
||||||
templateOptions?: any;
|
templateOptions?: any;
|
||||||
|
@ -68,9 +69,11 @@ YargsParser.command(
|
||||||
watch: argv.watch as boolean,
|
watch: argv.watch as boolean,
|
||||||
templateFileName: argv.template as string,
|
templateFileName: argv.template as string,
|
||||||
templateOptions: argv.templateOptions || {},
|
templateOptions: argv.templateOptions || {},
|
||||||
redocOptions: argv.options || {},
|
redocOptions: getObjectOrJSON(argv.options),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(config);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await serve(argv.port as number, argv.spec as string, config);
|
await serve(argv.port as number, argv.spec as string, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -99,6 +102,12 @@ YargsParser.command(
|
||||||
default: 'ReDoc documentation',
|
default: 'ReDoc documentation',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
yargs.options('disableGoogleFont', {
|
||||||
|
describe: 'Disable Google Font',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
yargs.option('cdn', {
|
yargs.option('cdn', {
|
||||||
describe: 'Do not include ReDoc source code into html page, use link to CDN instead',
|
describe: 'Do not include ReDoc source code into html page, use link to CDN instead',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
|
@ -108,15 +117,16 @@ YargsParser.command(
|
||||||
yargs.demandOption('spec');
|
yargs.demandOption('spec');
|
||||||
return yargs;
|
return yargs;
|
||||||
},
|
},
|
||||||
async argv => {
|
async (argv: any) => {
|
||||||
const config: Options = {
|
const config = {
|
||||||
ssr: true,
|
ssr: true,
|
||||||
output: argv.o as string,
|
output: argv.o as string,
|
||||||
cdn: argv.cdn as boolean,
|
cdn: argv.cdn as boolean,
|
||||||
title: argv.title as string,
|
title: argv.title as string,
|
||||||
|
disableGoogleFont: argv.disableGoogleFont as boolean,
|
||||||
templateFileName: argv.template as string,
|
templateFileName: argv.template as string,
|
||||||
templateOptions: argv.templateOptions || {},
|
templateOptions: argv.templateOptions || {},
|
||||||
redocOptions: argv.options || {},
|
redocOptions: getObjectOrJSON(argv.options),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -180,21 +190,34 @@ async function serve(port: number, pathToSpec: string, options: Options = {}) {
|
||||||
if (options.watch && existsSync(pathToSpec)) {
|
if (options.watch && existsSync(pathToSpec)) {
|
||||||
const pathToSpecDirectory = resolve(dirname(pathToSpec));
|
const pathToSpecDirectory = resolve(dirname(pathToSpec));
|
||||||
const watchOptions = {
|
const watchOptions = {
|
||||||
ignored: /(^|[\/\\])\../,
|
ignored: [/(^|[\/\\])\../, /___jb_[a-z]+___$/],
|
||||||
|
ignoreInitial: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const watcher = watch(pathToSpecDirectory, watchOptions);
|
const watcher = watch(pathToSpecDirectory, watchOptions);
|
||||||
const log = console.log.bind(console);
|
const log = console.log.bind(console);
|
||||||
|
|
||||||
|
const handlePath = async path => {
|
||||||
|
try {
|
||||||
|
spec = await loadAndBundleSpec(pathToSpec);
|
||||||
|
pageHTML = await getPageHTML(spec, pathToSpec, options);
|
||||||
|
log('Updated successfully');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error while updating: ', e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
watcher
|
watcher
|
||||||
.on('change', async path => {
|
.on('change', async path => {
|
||||||
log(`${path} changed, updating docs`);
|
log(`${path} changed, updating docs`);
|
||||||
try {
|
handlePath(path);
|
||||||
spec = await loadAndBundleSpec(pathToSpec);
|
})
|
||||||
pageHTML = await getPageHTML(spec, pathToSpec, options);
|
.on('add', async path => {
|
||||||
log('Updated successfully');
|
log(`File ${path} added, updating docs`);
|
||||||
} catch (e) {
|
handlePath(path);
|
||||||
console.error('Error while updating: ', e.message);
|
})
|
||||||
}
|
.on('addDir', path => {
|
||||||
|
log(`↗ Directory ${path} added. Files in here will trigger reload.`);
|
||||||
})
|
})
|
||||||
.on('error', error => console.error(`Watcher error: ${error}`))
|
.on('error', error => console.error(`Watcher error: ${error}`))
|
||||||
.on('ready', () => log(`👀 Watching ${pathToSpecDirectory} for changes...`));
|
.on('ready', () => log(`👀 Watching ${pathToSpecDirectory} for changes...`));
|
||||||
|
@ -218,7 +241,15 @@ async function bundle(pathToSpec, options: Options = {}) {
|
||||||
async function getPageHTML(
|
async function getPageHTML(
|
||||||
spec: any,
|
spec: any,
|
||||||
pathToSpec: string,
|
pathToSpec: string,
|
||||||
{ ssr, cdn, title, templateFileName, templateOptions, redocOptions = {} }: Options,
|
{
|
||||||
|
ssr,
|
||||||
|
cdn,
|
||||||
|
title,
|
||||||
|
disableGoogleFont,
|
||||||
|
templateFileName,
|
||||||
|
templateOptions,
|
||||||
|
redocOptions = {},
|
||||||
|
}: Options,
|
||||||
) {
|
) {
|
||||||
let html;
|
let html;
|
||||||
let css;
|
let css;
|
||||||
|
@ -261,6 +292,7 @@ async function getPageHTML(
|
||||||
: `<script>${redocStandaloneSrc}</script>`) + css
|
: `<script>${redocStandaloneSrc}</script>`) + css
|
||||||
: '<script src="redoc.standalone.js"></script>',
|
: '<script src="redoc.standalone.js"></script>',
|
||||||
title,
|
title,
|
||||||
|
disableGoogleFont,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -323,3 +355,15 @@ function handleError(error: Error) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getObjectOrJSON(options) {
|
||||||
|
try {
|
||||||
|
return options && typeof options === 'string'
|
||||||
|
? JSON.parse(options) : options
|
||||||
|
? options
|
||||||
|
: {};
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Encountered error:\n${options}\nis not a valid JSON.`);
|
||||||
|
handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "redoc-cli",
|
"name": "redoc-cli",
|
||||||
"version": "0.8.6",
|
"version": "0.9.2",
|
||||||
"description": "ReDoc's Command Line Interface",
|
"description": "ReDoc's Command Line Interface",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"bin": "index.js",
|
"bin": "index.js",
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
"node-libs-browser": "^2.2.1",
|
"node-libs-browser": "^2.2.1",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"redoc": "2.0.0-rc.13",
|
"redoc": "2.0.0-rc.16",
|
||||||
"styled-components": "^4.3.2",
|
"styled-components": "^4.3.2",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"yargs": "^13.3.0"
|
"yargs": "^13.3.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{{{redocHead}}}
|
{{{redocHead}}}
|
||||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
{{#unless disableGoogleFont}}<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">{{/unless}}
|
||||||
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet">
|
<link href="https://cdn.fontcdn.ir/Font/Persian/Vazir/Vazir.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -629,10 +629,10 @@ domain-browser@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||||
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
|
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
|
||||||
|
|
||||||
dompurify@^1.0.11:
|
dompurify@^2.0.3:
|
||||||
version "1.0.11"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-1.0.11.tgz#fe0f4a40d147f7cebbe31a50a1357539cfc1eb4d"
|
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.3.tgz#5cc4965a487d54aedba6ba9634b137cfbd7eb50d"
|
||||||
integrity sha512-XywCTXZtc/qCX3iprD1pIklRVk/uhl8BKpkTxr+ZyMVUzSUg7wkQXRBp/euJ5J5moa1QvfpvaPQVP71z1O59dQ==
|
integrity sha512-q006uOkD2JGSJgF0qBt7rVhUvUPBWCxpGayALmHvXx2iNlMfNVz7PDGeXEUjNGgIDjADz59VZCv6UE3U8XRWVw==
|
||||||
|
|
||||||
elliptic@^6.0.0:
|
elliptic@^6.0.0:
|
||||||
version "6.5.0"
|
version "6.5.0"
|
||||||
|
@ -1092,7 +1092,7 @@ mem@^4.0.0:
|
||||||
mimic-fn "^2.0.0"
|
mimic-fn "^2.0.0"
|
||||||
p-is-promise "^2.0.0"
|
p-is-promise "^2.0.0"
|
||||||
|
|
||||||
memoize-one@^5.0.0, memoize-one@^5.0.5:
|
memoize-one@^5.0.0, memoize-one@~5.0.5:
|
||||||
version "5.0.5"
|
version "5.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
|
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
|
||||||
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
|
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
|
||||||
|
@ -1161,10 +1161,10 @@ mobx-react-lite@1.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.4.0.tgz#193beb5fdddf17ae61542f65ff951d84db402351"
|
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.4.0.tgz#193beb5fdddf17ae61542f65ff951d84db402351"
|
||||||
integrity sha512-5xCuus+QITQpzKOjAOIQ/YxNhOl/En+PlNJF+5QU4Qxn9gnNMJBbweAdEW3HnuVQbfqDYEUnkGs5hmkIIStehg==
|
integrity sha512-5xCuus+QITQpzKOjAOIQ/YxNhOl/En+PlNJF+5QU4Qxn9gnNMJBbweAdEW3HnuVQbfqDYEUnkGs5hmkIIStehg==
|
||||||
|
|
||||||
mobx-react@^6.1.1:
|
mobx-react@^6.1.3:
|
||||||
version "6.1.1"
|
version "6.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.1.tgz#24a2c8a3393890fa732b4efd34cc6dcccf6e0e7a"
|
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.3.tgz#ad07880ea60cdcdb2a7e2a0d54e01379710cf00a"
|
||||||
integrity sha512-hjACWCTpxZf9Sv1YgWF/r6HS6Nsly1SYF22qBJeUE3j+FMfoptgjf8Zmcx2d6uzA07Cezwap5Cobq9QYa0MKUw==
|
integrity sha512-eT/jO9dYIoB1AlZwI2VC3iX0gPOeOIqZsiwg7tDJV1B7Z69h+TZZL3dgOE0UeS2zoHhGeKbP+K+OLeLMnnkGnA==
|
||||||
dependencies:
|
dependencies:
|
||||||
mobx-react-lite "1.4.0"
|
mobx-react-lite "1.4.0"
|
||||||
|
|
||||||
|
@ -1540,10 +1540,10 @@ react-dropdown@^1.6.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.3"
|
classnames "^2.2.3"
|
||||||
|
|
||||||
react-hot-loader@^4.12.10:
|
react-hot-loader@^4.12.14:
|
||||||
version "4.12.10"
|
version "4.12.14"
|
||||||
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.10.tgz#b3457c0f733423c4827c6d2672e50c9f8bedaf6b"
|
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.14.tgz#81ca06ffda0b90aad15d6069339f73ed6428340a"
|
||||||
integrity sha512-dX+ZUigxQijWLsKPnxc0khuCt2sYiZ1W59LgSBMOLeGSG3+HkknrTlnJu6BCNdhYxbEQkGvBsr7zXlNWYUIhAQ==
|
integrity sha512-ecxH4eBvEaJ9onT8vkEmK1FAAJUh1PqzGqds9S3k+GeihSp7nKAp4fOxytO+Ghr491LiBD38jaKyDXYnnpI9pQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-levenshtein "^2.0.6"
|
fast-levenshtein "^2.0.6"
|
||||||
global "^4.3.0"
|
global "^4.3.0"
|
||||||
|
@ -1602,35 +1602,35 @@ readdirp@^3.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.0.4"
|
picomatch "^2.0.4"
|
||||||
|
|
||||||
redoc@2.0.0-rc.13:
|
redoc@2.0.0-rc.16:
|
||||||
version "2.0.0-rc.13"
|
version "2.0.0-rc.16"
|
||||||
resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.13.tgz#243e4d003ca9bd45006c215d8856a3b1229ca8bb"
|
resolved "https://registry.yarnpkg.com/redoc/-/redoc-2.0.0-rc.16.tgz#01d5dafba6ae266a5934dc9904b87bc8a175b222"
|
||||||
integrity sha512-t0vlss1TIUknYXTI9RIZ1nRMyIW/pjo4KMMDFOMdRq5/8jopkNyf37q25BwBuAJfDxQV+tIUoy6o+rAAffeDkQ==
|
integrity sha512-5YWk7NBebYZ8xMbKXA1sD++QsSh7NbnB2sStJRKLeP/rU4oX586SIqHXl+MW1OhIZW44mYFMHpYzxpZKCllk9w==
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
decko "^1.2.0"
|
decko "^1.2.0"
|
||||||
dompurify "^1.0.11"
|
dompurify "^2.0.3"
|
||||||
eventemitter3 "^4.0.0"
|
eventemitter3 "^4.0.0"
|
||||||
json-pointer "^0.6.0"
|
json-pointer "^0.6.0"
|
||||||
json-schema-ref-parser "^6.1.0"
|
json-schema-ref-parser "^6.1.0"
|
||||||
lunr "2.3.6"
|
lunr "2.3.6"
|
||||||
mark.js "^8.11.1"
|
mark.js "^8.11.1"
|
||||||
marked "^0.7.0"
|
marked "^0.7.0"
|
||||||
memoize-one "^5.0.5"
|
memoize-one "~5.0.5"
|
||||||
mobx-react "^6.1.1"
|
mobx-react "^6.1.3"
|
||||||
openapi-sampler "1.0.0-beta.15"
|
openapi-sampler "1.0.0-beta.15"
|
||||||
perfect-scrollbar "^1.4.0"
|
perfect-scrollbar "^1.4.0"
|
||||||
polished "^3.4.1"
|
polished "^3.4.1"
|
||||||
prismjs "^1.17.1"
|
prismjs "^1.17.1"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-dropdown "^1.6.4"
|
react-dropdown "^1.6.4"
|
||||||
react-hot-loader "^4.12.10"
|
react-hot-loader "^4.12.14"
|
||||||
react-tabs "^3.0.0"
|
react-tabs "^3.0.0"
|
||||||
slugify "^1.3.4"
|
slugify "^1.3.5"
|
||||||
stickyfill "^1.1.1"
|
stickyfill "^1.1.1"
|
||||||
swagger2openapi "^5.3.1"
|
swagger2openapi "^5.3.1"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
uri-template-lite "^19.4.0"
|
url-template "^2.0.8"
|
||||||
|
|
||||||
reftools@^1.0.8:
|
reftools@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
|
@ -1782,10 +1782,10 @@ signal-exit@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||||
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
||||||
|
|
||||||
slugify@^1.3.4:
|
slugify@^1.3.5:
|
||||||
version "1.3.4"
|
version "1.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.4.tgz#78d2792d7222b55cd9fc81fa018df99af779efeb"
|
resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.5.tgz#90210678818b6d533cb060083aed0e8238133508"
|
||||||
integrity sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==
|
integrity sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA==
|
||||||
|
|
||||||
source-map@^0.5.0:
|
source-map@^0.5.0:
|
||||||
version "0.5.7"
|
version "0.5.7"
|
||||||
|
@ -2002,10 +2002,10 @@ uglify-js@^3.1.4:
|
||||||
commander "~2.20.0"
|
commander "~2.20.0"
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
uri-template-lite@^19.4.0:
|
url-template@^2.0.8:
|
||||||
version "19.4.0"
|
version "2.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/uri-template-lite/-/uri-template-lite-19.4.0.tgz#cbc2c072cf4931428a2f9d3aea36b8254a33cce5"
|
resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
|
||||||
integrity sha512-VY8dgwyMwnCztkzhq0cA/YhNmO+YZqow//5FdmgE2fZU/JPi+U0rPL7MRDi0F+Ch4vJ7nYidWzeWAeY7uywe9g==
|
integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE=
|
||||||
|
|
||||||
url@^0.11.0:
|
url@^0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
|
|
1
demo/.gitignore
vendored
Normal file
1
demo/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
intent.json
|
|
@ -1,8 +1,8 @@
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
servers:
|
servers:
|
||||||
- url: //petstore.swagger.io/v2
|
- url: https://petstore.swagger.io/v2
|
||||||
description: Default server
|
description: Default server
|
||||||
- url: //petstore.swagger.io/sandbox
|
- url: https://petstore.swagger.io/sandbox
|
||||||
description: Sandbox server
|
description: Sandbox server
|
||||||
info:
|
info:
|
||||||
description: |
|
description: |
|
||||||
|
@ -38,8 +38,6 @@ info:
|
||||||
OAuth2 - an open protocol to allow secure authorization in a simple
|
OAuth2 - an open protocol to allow secure authorization in a simple
|
||||||
and standard method from web, mobile and desktop applications.
|
and standard method from web, mobile and desktop applications.
|
||||||
|
|
||||||
<SecurityDefinitions />
|
|
||||||
|
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
title: Swagger Petstore
|
title: Swagger Petstore
|
||||||
termsOfService: 'http://swagger.io/terms/'
|
termsOfService: 'http://swagger.io/terms/'
|
||||||
|
@ -103,7 +101,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Invalid input
|
description: Invalid input
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
x-code-samples:
|
x-code-samples:
|
||||||
|
@ -151,7 +149,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Validation exception
|
description: Validation exception
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
x-code-samples:
|
x-code-samples:
|
||||||
|
@ -219,7 +217,7 @@ paths:
|
||||||
'405':
|
'405':
|
||||||
description: Invalid input
|
description: Invalid input
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
requestBody:
|
requestBody:
|
||||||
|
@ -258,7 +256,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid pet value
|
description: Invalid pet value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
'/pet/{petId}/uploadImage':
|
'/pet/{petId}/uploadImage':
|
||||||
|
@ -284,7 +282,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ApiResponse'
|
$ref: '#/components/schemas/ApiResponse'
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
requestBody:
|
requestBody:
|
||||||
|
@ -334,7 +332,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid status value
|
description: Invalid status value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
/pet/findByTags:
|
/pet/findByTags:
|
||||||
|
@ -374,7 +372,7 @@ paths:
|
||||||
'400':
|
'400':
|
||||||
description: Invalid tag value
|
description: Invalid tag value
|
||||||
security:
|
security:
|
||||||
- petstore_auth:
|
- authorization:
|
||||||
- 'write:pets'
|
- 'write:pets'
|
||||||
- 'read:pets'
|
- 'read:pets'
|
||||||
/store/inventory:
|
/store/inventory:
|
||||||
|
@ -925,7 +923,7 @@ components:
|
||||||
description: List of user object
|
description: List of user object
|
||||||
required: true
|
required: true
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
petstore_auth:
|
authorization:
|
||||||
description: |
|
description: |
|
||||||
Get access to data while protecting your account credentials.
|
Get access to data while protecting your account credentials.
|
||||||
OAuth2 is also a safer and more secure way to give you access.
|
OAuth2 is also a safer and more secure way to give you access.
|
||||||
|
|
993
demo/petstore.json
Normal file
993
demo/petstore.json
Normal file
|
@ -0,0 +1,993 @@
|
||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "Swagger Petstore",
|
||||||
|
"termsOfService": "http://swagger.io/terms/",
|
||||||
|
"contact": {
|
||||||
|
"email": "apiteam@swagger.io"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "Apache 2.0",
|
||||||
|
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"host": "petstore.swagger.io",
|
||||||
|
"basePath": "/v2",
|
||||||
|
"tags": [{
|
||||||
|
"name": "pet",
|
||||||
|
"description": "Everything about your Pets",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "http://swagger.io"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "store",
|
||||||
|
"description": "Access to Petstore orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "user",
|
||||||
|
"description": "Operations about user",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more about our store",
|
||||||
|
"url": "http://swagger.io"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schemes": [
|
||||||
|
"http"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/pet": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Add a new pet to the store",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "addPet",
|
||||||
|
"consumes": [
|
||||||
|
"application/json",
|
||||||
|
"application/xml"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "Pet object that needs to be added to the store",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Pet"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "Invalid input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Update an existing pet",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "updatePet",
|
||||||
|
"consumes": [
|
||||||
|
"application/json",
|
||||||
|
"application/xml"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "Pet object that needs to be added to the store",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Pet"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Pet not found"
|
||||||
|
},
|
||||||
|
"405": {
|
||||||
|
"description": "Validation exception"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/pet/findByStatus": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Finds Pets by status",
|
||||||
|
"description": "Multiple status values can be provided with comma separated strings",
|
||||||
|
"operationId": "findPetsByStatus",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "status",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Status values that need to be considered for filter",
|
||||||
|
"required": true,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"available",
|
||||||
|
"pending",
|
||||||
|
"sold"
|
||||||
|
],
|
||||||
|
"default": "available"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Pet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid status value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/pet/findByTags": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Finds Pets by tags",
|
||||||
|
"description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.",
|
||||||
|
"operationId": "findPetsByTags",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "tags",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Tags to filter by",
|
||||||
|
"required": true,
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Pet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid tag value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
"deprecated": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/pet/{petId}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Find pet by ID",
|
||||||
|
"description": "Returns a single pet",
|
||||||
|
"operationId": "getPetById",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "petId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of pet to return",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Pet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Pet not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"api_key": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Updates a pet in the store with form data",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "updatePetWithForm",
|
||||||
|
"consumes": [
|
||||||
|
"application/x-www-form-urlencoded"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "petId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of pet that needs to be updated",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"in": "formData",
|
||||||
|
"description": "Updated name of the pet",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "status",
|
||||||
|
"in": "formData",
|
||||||
|
"description": "Updated status of the pet",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"405": {
|
||||||
|
"description": "Invalid input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "Deletes a pet",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "deletePet",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "api_key",
|
||||||
|
"in": "header",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "petId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "Pet id to delete",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Pet not found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/pet/{petId}/uploadImage": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"pet"
|
||||||
|
],
|
||||||
|
"summary": "uploads an image",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "uploadFile",
|
||||||
|
"consumes": [
|
||||||
|
"multipart/form-data"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "petId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of pet to update",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "additionalMetadata",
|
||||||
|
"in": "formData",
|
||||||
|
"description": "Additional data to pass to server",
|
||||||
|
"required": false,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "file",
|
||||||
|
"in": "formData",
|
||||||
|
"description": "file to upload",
|
||||||
|
"required": false,
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ApiResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"petstore_auth": [
|
||||||
|
"write:pets",
|
||||||
|
"read:pets"
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/store/inventory": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"store"
|
||||||
|
],
|
||||||
|
"summary": "Returns pet inventories by status",
|
||||||
|
"description": "Returns a map of status codes to quantities",
|
||||||
|
"operationId": "getInventory",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [{
|
||||||
|
"api_key": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/store/order": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"store"
|
||||||
|
],
|
||||||
|
"summary": "Place an order for a pet",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "placeOrder",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "order placed for purchasing the pet",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Order"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Order"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid Order"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/store/order/{orderId}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"store"
|
||||||
|
],
|
||||||
|
"summary": "Find purchase order by ID",
|
||||||
|
"description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions",
|
||||||
|
"operationId": "getOrderById",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "orderId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of pet that needs to be fetched",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 10.0,
|
||||||
|
"minimum": 1.0,
|
||||||
|
"format": "int64"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Order"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Order not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"store"
|
||||||
|
],
|
||||||
|
"summary": "Delete purchase order by ID",
|
||||||
|
"description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors",
|
||||||
|
"operationId": "deleteOrder",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "orderId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of the order that needs to be deleted",
|
||||||
|
"required": true,
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1.0,
|
||||||
|
"format": "int64"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Order not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Create user",
|
||||||
|
"description": "This can only be done by the logged in user.",
|
||||||
|
"operationId": "createUser",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "Created user object",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "successful operation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user/createWithArray": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Creates list of users with given input array",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "createUsersWithArrayInput",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "List of user object",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "successful operation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user/createWithList": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Creates list of users with given input array",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "createUsersWithListInput",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "List of user object",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "successful operation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user/login": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Logs user into the system",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "loginUser",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "username",
|
||||||
|
"in": "query",
|
||||||
|
"description": "The user name for login",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "password",
|
||||||
|
"in": "query",
|
||||||
|
"description": "The password for login in clear text",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"X-Rate-Limit": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"description": "calls per hour allowed by the user"
|
||||||
|
},
|
||||||
|
"X-Expires-After": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "date in UTC when token expires"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid username/password supplied"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user/logout": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Logs out current logged in user session",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "logoutUser",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "successful operation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/user/{username}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Get user by user name",
|
||||||
|
"description": "",
|
||||||
|
"operationId": "getUserByName",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"description": "The name that needs to be fetched. Use user1 for testing. ",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "successful operation",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid username supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "User not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Updated user",
|
||||||
|
"description": "This can only be done by the logged in user.",
|
||||||
|
"operationId": "updateUser",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"description": "name that need to be updated",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"description": "Updated user object",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid user supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "User not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Delete user",
|
||||||
|
"description": "This can only be done by the logged in user.",
|
||||||
|
"operationId": "deleteUser",
|
||||||
|
"produces": [
|
||||||
|
"application/xml",
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"parameters": [{
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"description": "The name that needs to be deleted",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}],
|
||||||
|
"responses": {
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid username supplied"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "User not found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"petstore_auth": {
|
||||||
|
"type": "oauth2",
|
||||||
|
"authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
|
||||||
|
"flow": "implicit",
|
||||||
|
"scopes": {
|
||||||
|
"write:pets": "modify pets in your account",
|
||||||
|
"read:pets": "read your pets"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "api_key",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"Order": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"petId": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"shipDate": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Order Status",
|
||||||
|
"enum": [
|
||||||
|
"placed",
|
||||||
|
"approved",
|
||||||
|
"delivered"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"complete": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "Order"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"firstName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lastName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userStatus": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"description": "User Status"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "User"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Category": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "Category"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Tag": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "Tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Pet": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"photoUrls"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"$ref": "#/definitions/Category"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "doggie"
|
||||||
|
},
|
||||||
|
"photoUrls": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "photoUrl",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "array",
|
||||||
|
"xml": {
|
||||||
|
"name": "tag",
|
||||||
|
"wrapped": true
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "pet status in the store",
|
||||||
|
"enum": [
|
||||||
|
"available",
|
||||||
|
"pending",
|
||||||
|
"sold"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "Pet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ApiResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more about Swagger",
|
||||||
|
"url": "http://swagger.io"
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,8 @@ const specUrl =
|
||||||
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
|
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
|
||||||
|
|
||||||
let store;
|
let store;
|
||||||
const options: RedocRawOptions = { nativeScrollbars: false };
|
const headers = {};
|
||||||
|
const options: RedocRawOptions = { nativeScrollbars: false, enableConsole: true, providedByName: 'Intent ApiDocs by Nutanix', providedByUri: 'http://www.nutanix.com', additionalHeaders: headers };
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const spec = await loadAndBundleSpec(specUrl);
|
const spec = await loadAndBundleSpec(specUrl);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { renderToString } from 'react-dom/server';
|
|
||||||
import * as React from 'react';
|
|
||||||
import { ServerStyleSheet } from 'styled-components';
|
|
||||||
// @ts-ignore
|
|
||||||
import { Redoc, createStore } from '../../';
|
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { renderToString } from 'react-dom/server';
|
||||||
|
import { ServerStyleSheet } from 'styled-components';
|
||||||
|
|
||||||
|
import { createStore, Redoc } from '../../';
|
||||||
|
|
||||||
const yaml = require('yaml-js');
|
const yaml = require('yaml-js');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
@ -19,7 +19,7 @@ const server = http.createServer(async (request, response) => {
|
||||||
fs.createReadStream('bundles/redoc.standalone.js', 'utf8').pipe(response);
|
fs.createReadStream('bundles/redoc.standalone.js', 'utf8').pipe(response);
|
||||||
} else if (request.url === '/') {
|
} else if (request.url === '/') {
|
||||||
const spec = yaml.load(readFileSync(resolve(__dirname, '../openapi.yaml')));
|
const spec = yaml.load(readFileSync(resolve(__dirname, '../openapi.yaml')));
|
||||||
let store = await createStore(spec, 'path/to/spec.yaml');
|
const store = await createStore(spec, 'path/to/spec.yaml');
|
||||||
|
|
||||||
const sheet = new ServerStyleSheet();
|
const sheet = new ServerStyleSheet();
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,26 @@ const babelHotLoader = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let proxy = {};
|
||||||
|
let https = false;
|
||||||
|
//we are using our own proxy here
|
||||||
|
if (process.env.PROXY && process.env.USERNAME && process.env.PASSWORD) {
|
||||||
|
proxy = {
|
||||||
|
"/api": {
|
||||||
|
auth: `${process.env.USERNAME}:${process.env.PASSWORD}`,
|
||||||
|
target: process.env.PROXY,
|
||||||
|
"secure": false,
|
||||||
|
changeOrigin: true,
|
||||||
|
ws: true,
|
||||||
|
xfwd: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
https = true;
|
||||||
|
console.log('Using proxy configuration provided with command line, https in use.\n');
|
||||||
|
} else {
|
||||||
|
console.log('Using proxy from PC/PE local server\n');
|
||||||
|
}
|
||||||
|
|
||||||
export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) => ({
|
export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) => ({
|
||||||
entry: [
|
entry: [
|
||||||
root('../src/polyfills.ts'),
|
root('../src/polyfills.ts'),
|
||||||
|
@ -79,8 +99,12 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
|
||||||
port: 9090,
|
port: 9090,
|
||||||
disableHostCheck: true,
|
disableHostCheck: true,
|
||||||
stats: 'minimal',
|
stats: 'minimal',
|
||||||
|
https,
|
||||||
|
proxy,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
devtool: 'source-map',
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||||
alias:
|
alias:
|
||||||
|
|
13
package.json
13
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "redoc",
|
"name": "redoc",
|
||||||
"version": "2.0.0-rc.14",
|
"version": "2.0.0-rc.16",
|
||||||
"description": "ReDoc",
|
"description": "ReDoc",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -70,7 +70,9 @@
|
||||||
"@types/mark.js": "^8.11.4",
|
"@types/mark.js": "^8.11.4",
|
||||||
"@types/marked": "^0.6.5",
|
"@types/marked": "^0.6.5",
|
||||||
"@types/prismjs": "^1.16.0",
|
"@types/prismjs": "^1.16.0",
|
||||||
|
"@types/promise": "^7.1.30",
|
||||||
"@types/prop-types": "^15.7.1",
|
"@types/prop-types": "^15.7.1",
|
||||||
|
"@types/qs": "^6.5.1",
|
||||||
"@types/react": "^16.8.23",
|
"@types/react": "^16.8.23",
|
||||||
"@types/react-dom": "^16.8.5",
|
"@types/react-dom": "^16.8.5",
|
||||||
"@types/react-hot-loader": "^4.1.0",
|
"@types/react-hot-loader": "^4.1.0",
|
||||||
|
@ -133,6 +135,9 @@
|
||||||
"styled-components": "^4.1.1"
|
"styled-components": "^4.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ajv": "^6.4.0",
|
||||||
|
"ajv-errors": "^1.0.0",
|
||||||
|
"brace": "^0.11.1",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"decko": "^1.2.0",
|
"decko": "^1.2.0",
|
||||||
"dompurify": "^1.0.11",
|
"dompurify": "^1.0.11",
|
||||||
|
@ -149,14 +154,18 @@
|
||||||
"polished": "^3.4.1",
|
"polished": "^3.4.1",
|
||||||
"prismjs": "^1.17.1",
|
"prismjs": "^1.17.1",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
"qs": "^6.5.2",
|
||||||
|
"react-ace": "^6.0.0",
|
||||||
"react-dropdown": "^1.6.4",
|
"react-dropdown": "^1.6.4",
|
||||||
"react-hot-loader": "^4.12.10",
|
"react-hot-loader": "^4.12.10",
|
||||||
|
"react-switch": "^5.0.1",
|
||||||
"react-tabs": "^3.0.0",
|
"react-tabs": "^3.0.0",
|
||||||
"slugify": "^1.3.4",
|
"slugify": "^1.3.4",
|
||||||
"stickyfill": "^1.1.1",
|
"stickyfill": "^1.1.1",
|
||||||
"swagger2openapi": "^5.3.1",
|
"swagger2openapi": "^5.3.1",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"uri-template-lite": "^19.4.0"
|
"uri-template-lite": "^19.4.0",
|
||||||
|
"url-template": "^2.0.8"
|
||||||
},
|
},
|
||||||
"bundlesize": [
|
"bundlesize": [
|
||||||
{
|
{
|
||||||
|
|
43
src/common-elements/SwitchBox.tsx
Normal file
43
src/common-elements/SwitchBox.tsx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import Switch from 'react-switch';
|
||||||
|
import {FlexLayout} from './index';
|
||||||
|
|
||||||
|
import styled from '../styled-components';
|
||||||
|
|
||||||
|
const CustomFlexLayout = styled(FlexLayout)`
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface LabelProps {
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Label = styled.label<LabelProps>`
|
||||||
|
color: ${props => props.active ? props.theme.colors.success.main : props.theme.colors.text.secondary}
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 120%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface TryItOutProps {
|
||||||
|
label: string;
|
||||||
|
checked: boolean;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SwitchBox extends React.PureComponent<TryItOutProps> {
|
||||||
|
id = 'toggle-id-' + Date.now();
|
||||||
|
render() {
|
||||||
|
const { label, checked, onClick } = this.props;
|
||||||
|
return (
|
||||||
|
<CustomFlexLayout>
|
||||||
|
<Switch
|
||||||
|
id={this.id}
|
||||||
|
onChange={onClick}
|
||||||
|
checked={checked}
|
||||||
|
uncheckedIcon={false}
|
||||||
|
/>
|
||||||
|
<Label active={checked} htmlFor={this.id}>{label}</Label>
|
||||||
|
</CustomFlexLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
23
src/common-elements/buttons.ts
Normal file
23
src/common-elements/buttons.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import styled from '../styled-components';
|
||||||
|
|
||||||
|
export const Button = styled.button`
|
||||||
|
background: #248fb2;
|
||||||
|
border-radius: 0px;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.929em;
|
||||||
|
padding: 5px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SubmitButton = styled(Button)`
|
||||||
|
background: ${props => props.theme.colors.primary.main}
|
||||||
|
padding: 10px 30px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
margin: 1em 0;
|
||||||
|
min-width: 60px;
|
||||||
|
font-weight: bold;
|
||||||
|
order: 1;
|
||||||
|
`;
|
|
@ -9,3 +9,6 @@ export * from './mixins';
|
||||||
export * from './tabs';
|
export * from './tabs';
|
||||||
export * from './samples';
|
export * from './samples';
|
||||||
export * from './perfect-scrollbar';
|
export * from './perfect-scrollbar';
|
||||||
|
export * from './toggle';
|
||||||
|
export * from './input';
|
||||||
|
export * from './buttons';
|
||||||
|
|
8
src/common-elements/input.tsx
Normal file
8
src/common-elements/input.tsx
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import styled from '../styled-components';
|
||||||
|
|
||||||
|
export const TextField = styled.input`
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0.5em;
|
||||||
|
border: 1px solid rgba(38,50,56,0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
`;
|
|
@ -1,16 +1,18 @@
|
||||||
import { SECTION_ATTR } from '../services/MenuStore';
|
import { SECTION_ATTR } from '../services/MenuStore';
|
||||||
import styled, { media } from '../styled-components';
|
import styled, { media } from '../styled-components';
|
||||||
|
|
||||||
export const MiddlePanel = styled.div`
|
export const MiddlePanel = styled.div<{ compact?: boolean }>`
|
||||||
width: calc(100% - ${props => props.theme.rightPanel.width});
|
width: calc(100% - ${props => props.theme.rightPanel.width});
|
||||||
padding: 0 ${props => props.theme.spacing.sectionHorizontal}px;
|
padding: 0 ${props => props.theme.spacing.sectionHorizontal}px;
|
||||||
direction: ${props => props.theme.typography.direction || 'ltr'};
|
direction: ${props => props.theme.typography.direction || 'ltr'};
|
||||||
text-align: ${props => (props.theme.typography.direction === 'rtl') ? 'right' : 'inherit'};
|
text-align: ${props => (props.theme.typography.direction === 'rtl') ? 'right' : 'inherit'};
|
||||||
|
|
||||||
${media.lessThan('medium', true)`
|
${({ compact, theme }) =>
|
||||||
|
media.lessThan('medium', true)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: ${props =>
|
padding: ${`${compact ? 0 : theme.spacing.sectionVertical}px ${
|
||||||
`${props.theme.spacing.sectionVertical}px ${props.theme.spacing.sectionHorizontal}px`};
|
theme.spacing.sectionHorizontal
|
||||||
|
}px`};
|
||||||
`};
|
`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -73,3 +75,13 @@ export const Row = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`};
|
`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const FlexLayout = styled.div`
|
||||||
|
align-items: flex-end;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FlexLayoutReverse = styled(FlexLayout)`
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
`;
|
||||||
|
|
10
src/common-elements/toggle.tsx
Normal file
10
src/common-elements/toggle.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import styled from '../styled-components';
|
||||||
|
|
||||||
|
export const Toggle = styled.input`
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0.5em;
|
||||||
|
color: palevioletred;
|
||||||
|
background: papayawhip;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
`;
|
78
src/components/Console/ConsoleEditor.tsx
Normal file
78
src/components/Console/ConsoleEditor.tsx
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import AceEditor from 'react-ace';
|
||||||
|
|
||||||
|
import 'brace/mode/curly';
|
||||||
|
import 'brace/mode/json';
|
||||||
|
import 'brace/theme/github';
|
||||||
|
import 'brace/theme/monokai';
|
||||||
|
|
||||||
|
import {MediaTypeModel} from '../../services/models';
|
||||||
|
import {ConsoleEditorWrapper} from './ConsoleEditorWrapper';
|
||||||
|
|
||||||
|
export interface ConsoleEditorProps {
|
||||||
|
mediaTypes: MediaTypeModel[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class ConsoleEditor extends React.Component<ConsoleEditorProps> {
|
||||||
|
|
||||||
|
editor: any;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { mediaTypes } = this.props;
|
||||||
|
|
||||||
|
if (!mediaTypes.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let sample = {};
|
||||||
|
for (const mediaType of mediaTypes) {
|
||||||
|
if (mediaType.name.indexOf('json') > -1) {
|
||||||
|
if (mediaType.examples) {
|
||||||
|
const example = getDefaultOrFirst(mediaType.examples);
|
||||||
|
sample = example && example.value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConsoleEditorWrapper>
|
||||||
|
<AceEditor
|
||||||
|
setOptions={{
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableLiveAutocompletion: true,
|
||||||
|
enableSnippets: true,
|
||||||
|
showLineNumbers: true,
|
||||||
|
tabSize: 2,
|
||||||
|
fontFamily: 'Courier,monospace,Vazir',
|
||||||
|
displayIndentGuides: false,
|
||||||
|
}}
|
||||||
|
fontSize={13}
|
||||||
|
style={{
|
||||||
|
lineHeight: '23px',
|
||||||
|
}}
|
||||||
|
mode="json"
|
||||||
|
name="request-builder-editor"
|
||||||
|
editorProps={{ $blockScrolling: true }}
|
||||||
|
value={JSON.stringify(sample, null, 2)}
|
||||||
|
ref={(ace: AceEditor) => (this.editor = ace)}
|
||||||
|
/>
|
||||||
|
</ConsoleEditorWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultOrFirst(object) {
|
||||||
|
if (typeof object === 'object') {
|
||||||
|
if (typeof object.default === 'object') {
|
||||||
|
return object.default;
|
||||||
|
} else {
|
||||||
|
return object[Object.keys(object)[0]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
77
src/components/Console/ConsoleEditorWrapper.ts
Normal file
77
src/components/Console/ConsoleEditorWrapper.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import {lighten} from 'polished';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
|
export const ConsoleEditorWrapper = styled.div`
|
||||||
|
font-family: ${props => props.theme.typography.code.fontFamily};
|
||||||
|
font-size: ${props => props.theme.typography.code.fontSize} !important;
|
||||||
|
direction: ltr;
|
||||||
|
white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
|
||||||
|
contain: content;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: #11171a !important;
|
||||||
|
padding: 5px 0;
|
||||||
|
|
||||||
|
& .ace_editor {
|
||||||
|
background: #11171a !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_marker-layer .ace_selection, & .ace_editor .ace_marker-layer .ace_selected-word {
|
||||||
|
background: ${lighten(0.05, '#11171a')} !important;
|
||||||
|
border-color: ${lighten(0.05, '#11171a')} !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_marker-layer .ace_active-line {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_line, & .ace_editor .ace_cursor {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_marker-layer .ace_bracket {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_line .ace_fold {
|
||||||
|
background: none !important;
|
||||||
|
color: #aaa;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_line .ace_fold:hover {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_string {
|
||||||
|
color: #71e4ff;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_variable {
|
||||||
|
color: #a0fbaa;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_indent-guide {
|
||||||
|
background: none;
|
||||||
|
color: rgba(255, 255, 255, 0.3)
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_indent-guide::after {
|
||||||
|
content: "|";
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter {
|
||||||
|
background: ${lighten(0.01, '#11171a')} !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_fold-widget {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_fold-widget.ace_open::after {
|
||||||
|
content: "-";
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_fold-widget.ace_closed::after {
|
||||||
|
content: "+";
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_gutter-active-line {
|
||||||
|
background: rgba(0, 0, 0, 0.2) !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_gutter-cell.ace_error {
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
& .ace_editor .ace_gutter .ace_gutter-cell.ace_error::before {
|
||||||
|
position: absolute;
|
||||||
|
color: red;
|
||||||
|
content: "X";
|
||||||
|
left: 0.5em;
|
||||||
|
}
|
||||||
|
`;
|
172
src/components/Console/ConsoleViewer.tsx
Normal file
172
src/components/Console/ConsoleViewer.tsx
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { SecuritySchemeModel } from '../../../typings/services/models';
|
||||||
|
import { SubmitButton } from '../../common-elements/buttons';
|
||||||
|
import { FlexLayoutReverse } from '../../common-elements/panels';
|
||||||
|
import { FieldModel, OperationModel, SecuritySchemesModel } from '../../services/models';
|
||||||
|
import { ConsoleResponse } from '../ConsoleResponse/Response';
|
||||||
|
import { ConsoleEditor } from './ConsoleEditor';
|
||||||
|
|
||||||
|
const qs = require('qs');
|
||||||
|
|
||||||
|
export interface ConsoleViewerProps {
|
||||||
|
operation: OperationModel;
|
||||||
|
additionalHeaders?: object;
|
||||||
|
queryParamPrefix?: string;
|
||||||
|
queryParamSuffix?: string;
|
||||||
|
securitySchemes: SecuritySchemesModel;
|
||||||
|
urlIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConsoleViewerState {
|
||||||
|
result: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Schema {
|
||||||
|
_$ref?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class ConsoleViewer extends React.Component<ConsoleViewerProps, ConsoleViewerState> {
|
||||||
|
operation: OperationModel;
|
||||||
|
additionalHeaders: object;
|
||||||
|
visited = new Set();
|
||||||
|
private consoleEditor: any;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
result: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
onClickSend = async () => {
|
||||||
|
const ace = this.consoleEditor && this.consoleEditor.editor;
|
||||||
|
const { operation, securitySchemes: {schemes}, additionalHeaders = {}, urlIndex = 0 } = this.props;
|
||||||
|
|
||||||
|
let value = ace && ace.editor.getValue();
|
||||||
|
|
||||||
|
const content = operation.requestBody && operation.requestBody.content;
|
||||||
|
const mediaType = content && content.mediaTypes[content.activeMimeIdx];
|
||||||
|
const endpoint = {
|
||||||
|
method: operation.httpVerb,
|
||||||
|
path: operation.servers[urlIndex].url + operation.path,
|
||||||
|
};
|
||||||
|
if (value) {
|
||||||
|
value = JSON.parse(value);
|
||||||
|
}
|
||||||
|
const contentType = mediaType && mediaType.name || 'application/json';
|
||||||
|
const contentTypeHeader = { 'Content-Type': contentType };
|
||||||
|
|
||||||
|
const schemeMapper: Map<string, SecuritySchemeModel> = new Map<string, SecuritySchemeModel>();
|
||||||
|
schemes.forEach(scheme => {
|
||||||
|
schemeMapper.set(scheme.id, scheme);
|
||||||
|
});
|
||||||
|
|
||||||
|
const securityHeaders: Dict<string | undefined> = {};
|
||||||
|
|
||||||
|
operation.security.forEach(({schemes: [{ id }]}) => {
|
||||||
|
if (schemeMapper.has(id)) {
|
||||||
|
// this part of code needs a ts-ignore because typescript couldn't detect that schemeMapper.get(id) -
|
||||||
|
// has been checked to avoid token of undefined.
|
||||||
|
// @ts-ignore
|
||||||
|
securityHeaders[id] = schemeMapper.get(id).token;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const headers = { ...additionalHeaders, ...contentTypeHeader, ...securityHeaders };
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = await this.invoke(endpoint, value, headers);
|
||||||
|
this.setState({
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.setState({
|
||||||
|
result: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a url like foo/bar/{uuid} uuid will be replaced with what user has typed in.
|
||||||
|
*/
|
||||||
|
addParamsToUrl(url: string, params: FieldModel[]) {
|
||||||
|
const queryParamPrefix = '{';
|
||||||
|
const queryParamSuffix = '}';
|
||||||
|
|
||||||
|
for (const fieldModel of params) {
|
||||||
|
if (url.indexOf(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`) > -1 && fieldModel.$value.length > 0) {
|
||||||
|
url = url.replace(`${queryParamPrefix}${fieldModel.name}${queryParamSuffix}`, fieldModel.$value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.split(queryParamPrefix).length > 1) {
|
||||||
|
throw Error(`** we have missing query params ** ${url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async invoke(endpoint, body, headers = {}) {
|
||||||
|
try {
|
||||||
|
const { operation } = this.props;
|
||||||
|
let url = this.addParamsToUrl(endpoint.path, operation.parameters || []);
|
||||||
|
if (endpoint.method.toLocaleLowerCase() === 'get') {
|
||||||
|
url = url + '?' + qs.stringify(body || '');
|
||||||
|
}
|
||||||
|
const myHeaders = new Headers();
|
||||||
|
for (const [key, value] of Object.entries(headers)) {
|
||||||
|
myHeaders.append(key, `${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = new Request(url, {
|
||||||
|
method: endpoint.method,
|
||||||
|
redirect: 'manual',
|
||||||
|
headers: myHeaders,
|
||||||
|
body: (body) ? JSON.stringify(body) : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await fetch(request);
|
||||||
|
const content = await response.json();
|
||||||
|
const { ok, status, statusText, redirected } = response;
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
ok,
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
redirected,
|
||||||
|
headers: response.headers,
|
||||||
|
url: response.url,
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { operation } = this.props;
|
||||||
|
const requestBodyContent = operation.requestBody && operation.requestBody.content && operation.requestBody.content;
|
||||||
|
const hasBodySample = requestBodyContent && requestBodyContent.hasSample;
|
||||||
|
const mediaTypes = (requestBodyContent && requestBodyContent.mediaTypes) ? requestBodyContent.mediaTypes : [];
|
||||||
|
const { result } = this.state;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3> Request </h3>
|
||||||
|
{hasBodySample && (
|
||||||
|
<ConsoleEditor
|
||||||
|
mediaTypes={mediaTypes}
|
||||||
|
ref={(editor: any) => (this.consoleEditor = editor)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<FlexLayoutReverse>
|
||||||
|
<SubmitButton onClick={this.onClickSend} >Send Request</SubmitButton>
|
||||||
|
</FlexLayoutReverse>
|
||||||
|
{result &&
|
||||||
|
<ConsoleResponse response={result} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
2
src/components/Console/index.ts
Normal file
2
src/components/Console/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './ConsoleEditor';
|
||||||
|
export * from './ConsoleViewer';
|
119
src/components/ConsoleResponse/Response.tsx
Normal file
119
src/components/ConsoleResponse/Response.tsx
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { SourceCodeWithCopy } from '..';
|
||||||
|
import { RightPanelHeader } from '../../common-elements';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
|
import { JsonViewer } from '../JsonViewer/JsonViewer';
|
||||||
|
|
||||||
|
interface ConsoleResponseProps {
|
||||||
|
response: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConsoleResponseState {
|
||||||
|
collapse: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConsoleResponse extends React.PureComponent<ConsoleResponseProps, ConsoleResponseState> {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { collapse: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
changeCollapse = () => {
|
||||||
|
this.setState({collapse: !this.state.collapse});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { response: { headers, type, status, statusText, content } } = this.props;
|
||||||
|
const collapse = this.state.collapse;
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<RightPanelHeader> status: </RightPanelHeader>
|
||||||
|
<StatusWrapper className={'status-' + type}> {status} {statusText}</StatusWrapper>
|
||||||
|
<RightPanelHeader> Response Payload </RightPanelHeader>
|
||||||
|
<JsonWrapper>
|
||||||
|
<JsonViewer data={content!} />
|
||||||
|
</JsonWrapper>
|
||||||
|
<RightPanelHeader> Response Headers</RightPanelHeader>
|
||||||
|
<HeaderWrapper>
|
||||||
|
<SourceCodeWrapper className={'collapse-' + collapse}>
|
||||||
|
<SourceCodeWithCopy lang="json" source={JSON.stringify(headers, null, 2)}/>
|
||||||
|
</SourceCodeWrapper>
|
||||||
|
{
|
||||||
|
collapse &&
|
||||||
|
<ShowMore onClick={this.changeCollapse}>
|
||||||
|
<u>+ show undocumented response headers</u>
|
||||||
|
</ShowMore>
|
||||||
|
}
|
||||||
|
</HeaderWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const HeaderWrapper = styled.div`
|
||||||
|
color: white;
|
||||||
|
background-color: ${props => props.theme.codeSample.backgroundColor};
|
||||||
|
padding: 10px 0 18px;
|
||||||
|
margin: 10px 0;
|
||||||
|
height: 100%;
|
||||||
|
div div div {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
div pre span:first-child {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
div pre span:last-child {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
div pre {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SourceCodeWrapper = styled.div`
|
||||||
|
&.collapse-false {
|
||||||
|
height: 89px;
|
||||||
|
}
|
||||||
|
&.collapse-true {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const JsonWrapper = styled.div`
|
||||||
|
color: white;
|
||||||
|
background-color: ${props => props.theme.codeSample.backgroundColor};
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StatusWrapper = styled.div`
|
||||||
|
&.status-success {
|
||||||
|
color: #00ff1c;
|
||||||
|
}
|
||||||
|
&.status-redirect {
|
||||||
|
color: ${props => props.theme.colors.responses.redirect.color};
|
||||||
|
}
|
||||||
|
&.status-info {
|
||||||
|
color: ${props => props.theme.colors.responses.info.color};
|
||||||
|
}
|
||||||
|
&.status-error {
|
||||||
|
color: ${props => props.theme.colors.responses.error.color};
|
||||||
|
}
|
||||||
|
color: white;
|
||||||
|
background-color: ${props => props.theme.codeSample.backgroundColor};
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ShowMore = styled.div`
|
||||||
|
text-align: center;
|
||||||
|
u {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -1,35 +1,40 @@
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { AppStore } from '../../services';
|
||||||
|
|
||||||
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
||||||
import { AdvancedMarkdown } from '../Markdown/AdvancedMarkdown';
|
import { AdvancedMarkdown } from '../Markdown/AdvancedMarkdown';
|
||||||
|
|
||||||
import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
import { H1, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
||||||
import { ContentItemModel } from '../../services/MenuBuilder';
|
import { ContentItemModel } from '../../services/MenuBuilder';
|
||||||
import { GroupModel, OperationModel } from '../../services/models';
|
import { GroupModel } from '../../services/models';
|
||||||
import { Operation } from '../Operation/Operation';
|
import { Operation } from '../Operation/Operation';
|
||||||
|
|
||||||
@observer
|
export interface ContentItemsProps {
|
||||||
export class ContentItems extends React.Component<{
|
|
||||||
items: ContentItemModel[];
|
items: ContentItemModel[];
|
||||||
}> {
|
store: AppStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class ContentItems extends React.Component<ContentItemsProps> {
|
||||||
render() {
|
render() {
|
||||||
const items = this.props.items;
|
const { items, store } = this.props;
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return items.map(item => <ContentItem item={item} key={item.id} />);
|
return items.map(item => <ContentItem store={store} item={item} key={item.id} />);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContentItemProps {
|
export interface ContentItemProps {
|
||||||
item: ContentItemModel;
|
item: ContentItemModel;
|
||||||
|
store: AppStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ContentItem extends React.Component<ContentItemProps> {
|
export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
render() {
|
render() {
|
||||||
const item = this.props.item;
|
const { item, store } = this.props;
|
||||||
let content;
|
let content;
|
||||||
const { type } = item;
|
const { type } = item;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -41,7 +46,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
content = <SectionItem {...this.props} />;
|
content = <SectionItem {...this.props} />;
|
||||||
break;
|
break;
|
||||||
case 'operation':
|
case 'operation':
|
||||||
content = <OperationItem item={item as any} />;
|
content = <Operation securitySchemes={store.spec.securitySchemes} operation={item as any} />;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content = <SectionItem {...this.props} />;
|
content = <SectionItem {...this.props} />;
|
||||||
|
@ -54,13 +59,13 @@ export class ContentItem extends React.Component<ContentItemProps> {
|
||||||
{content}
|
{content}
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
{item.items && <ContentItems items={item.items} />}
|
{item.items && <ContentItems store={store} items={item.items} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const middlePanelWrap = component => <MiddlePanel>{component}</MiddlePanel>;
|
const middlePanelWrap = component => <MiddlePanel compact={true}>{component}</MiddlePanel>;
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class SectionItem extends React.Component<ContentItemProps> {
|
export class SectionItem extends React.Component<ContentItemProps> {
|
||||||
|
@ -71,7 +76,7 @@ export class SectionItem extends React.Component<ContentItemProps> {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Row>
|
<Row>
|
||||||
<MiddlePanel>
|
<MiddlePanel compact={level !== 1}>
|
||||||
<Header>
|
<Header>
|
||||||
<ShareLink to={this.props.item.id} />
|
<ShareLink to={this.props.item.id} />
|
||||||
{name}
|
{name}
|
||||||
|
@ -90,12 +95,3 @@ export class SectionItem extends React.Component<ContentItemProps> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
|
||||||
export class OperationItem extends React.Component<{
|
|
||||||
item: OperationModel;
|
|
||||||
}> {
|
|
||||||
render() {
|
|
||||||
return <Operation operation={this.props.item} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ShelfIcon } from '../../common-elements';
|
import { ShelfIcon } from '../../common-elements';
|
||||||
import { OperationModel } from '../../services';
|
import { ClipboardService, OperationModel } from '../../services';
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
import { Markdown } from '../Markdown/Markdown';
|
||||||
import { OptionsContext } from '../OptionsProvider';
|
import { OptionsContext } from '../OptionsProvider';
|
||||||
import { SelectOnClick } from '../SelectOnClick/SelectOnClick';
|
import { SelectOnClick } from '../SelectOnClick/SelectOnClick';
|
||||||
|
|
||||||
import { getBasePath } from '../../utils';
|
import { expandDefaultServerVariables, getBasePath } from '../../utils';
|
||||||
import {
|
import {
|
||||||
EndpointInfo,
|
EndpointInfo,
|
||||||
HttpVerb,
|
HttpVerb,
|
||||||
|
@ -21,10 +21,13 @@ export interface EndpointProps {
|
||||||
|
|
||||||
hideHostname?: boolean;
|
hideHostname?: boolean;
|
||||||
inverted?: boolean;
|
inverted?: boolean;
|
||||||
|
handleUrl: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EndpointState {
|
export interface EndpointState {
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
|
selectedItem: number;
|
||||||
|
tooltipShown: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
|
@ -32,6 +35,8 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
|
selectedItem: 0,
|
||||||
|
tooltipShown: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +53,9 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
<OptionsContext.Consumer>
|
<OptionsContext.Consumer>
|
||||||
{options => (
|
{options => (
|
||||||
<OperationEndpointWrap>
|
<OperationEndpointWrap>
|
||||||
|
<div className={this.state.tooltipShown === true ? 'showToolTip' : 'hideToolTip'}>
|
||||||
|
Copied
|
||||||
|
</div>
|
||||||
<EndpointInfo onClick={this.toggle} expanded={expanded} inverted={inverted}>
|
<EndpointInfo onClick={this.toggle} expanded={expanded} inverted={inverted}>
|
||||||
<HttpVerb type={operation.httpVerb}> {operation.httpVerb}</HttpVerb>{' '}
|
<HttpVerb type={operation.httpVerb}> {operation.httpVerb}</HttpVerb>{' '}
|
||||||
<ServerRelativeURL>{operation.path}</ServerRelativeURL>
|
<ServerRelativeURL>{operation.path}</ServerRelativeURL>
|
||||||
|
@ -60,16 +68,19 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
/>
|
/>
|
||||||
</EndpointInfo>
|
</EndpointInfo>
|
||||||
<ServersOverlay expanded={expanded}>
|
<ServersOverlay expanded={expanded}>
|
||||||
{operation.servers.map(server => {
|
{operation.servers.map((server, index) => {
|
||||||
|
const normalizedUrl = options.expandDefaultServerVariables
|
||||||
|
? expandDefaultServerVariables(server.url, server.variables)
|
||||||
|
: server.url;
|
||||||
return (
|
return (
|
||||||
<ServerItem key={server.url}>
|
<ServerItem className={this.state.selectedItem === index ? 'selected' : ''} key={normalizedUrl}>
|
||||||
<Markdown source={server.description || ''} compact={true} />
|
<Markdown onSelectUrl={this.handleUrl.bind(this, index)} source={server.description || ''} compact={true} />
|
||||||
<SelectOnClick>
|
<SelectOnClick onSelectUrl={this.handleUrl.bind(this, index)}>
|
||||||
<ServerUrl>
|
<ServerUrl>
|
||||||
<span>
|
<span>
|
||||||
{hideHostname || options.hideHostname
|
{hideHostname || options.hideHostname
|
||||||
? getBasePath(server.url)
|
? getBasePath(normalizedUrl)
|
||||||
: server.url}
|
: normalizedUrl}
|
||||||
</span>
|
</span>
|
||||||
{operation.path}
|
{operation.path}
|
||||||
</ServerUrl>
|
</ServerUrl>
|
||||||
|
@ -83,4 +94,19 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
|
||||||
</OptionsContext.Consumer>
|
</OptionsContext.Consumer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUrl(url: number) {
|
||||||
|
this.props.handleUrl(url);
|
||||||
|
this.setState({
|
||||||
|
selectedItem: url,
|
||||||
|
expanded: false,
|
||||||
|
tooltipShown: true,
|
||||||
|
});
|
||||||
|
ClipboardService.copyCustom(this.props.operation.servers[url].url + this.props.operation.path);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setState({
|
||||||
|
tooltipShown: false,
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,26 @@ export const OperationEndpointWrap = styled.div`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
.showToolTip {
|
||||||
|
visibility: initial;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
padding: 3px;
|
||||||
|
position: initial;
|
||||||
|
width: 53px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
};
|
||||||
|
.hideToolTip {
|
||||||
|
visibility:hidden;
|
||||||
|
padding: 3px;
|
||||||
|
position: initial;
|
||||||
|
width: 53px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ServerRelativeURL = styled.span`
|
export const ServerRelativeURL = styled.span`
|
||||||
|
@ -66,16 +86,28 @@ export const ServersOverlay = styled.div<{ expanded: boolean }>`
|
||||||
|
|
||||||
export const ServerItem = styled.div`
|
export const ServerItem = styled.div`
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
background-color: #002c2d;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
&.selected {
|
||||||
|
background-color: #3c7173;
|
||||||
|
}
|
||||||
|
div:first-child {
|
||||||
|
width: 20%;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ServerUrl = styled.div`
|
export const ServerUrl = styled.div`
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 5px;
|
user-select: none;
|
||||||
border: 1px solid #ccc;
|
padding: 5px !important;
|
||||||
background: #fff;
|
background-color: #ffffff33;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
color: ${props => props.theme.colors.primary.main};
|
width: 100% !important;
|
||||||
|
color: #00ff1c;
|
||||||
> span {
|
> span {
|
||||||
color: ${props => props.theme.colors.text.primary};
|
color: white;
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
WrappedShelfIcon,
|
WrappedShelfIcon,
|
||||||
} from '../../common-elements/fields-layout';
|
} from '../../common-elements/fields-layout';
|
||||||
|
|
||||||
import { ShelfIcon } from '../../common-elements/';
|
import { ShelfIcon, TextField } from '../../common-elements/';
|
||||||
|
|
||||||
import { FieldModel } from '../../services/models';
|
import { FieldModel } from '../../services/models';
|
||||||
import { Schema, SchemaOptions } from '../Schema/Schema';
|
import { Schema, SchemaOptions } from '../Schema/Schema';
|
||||||
|
@ -33,6 +33,12 @@ export class Field extends React.Component<FieldProps> {
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
this.props.field.toggle();
|
this.props.field.toggle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onFieldChange = e => {
|
||||||
|
console.log('Textfield value is ' + e.target.placeholder + ' - ' + e.target.value);
|
||||||
|
this.props.field.setValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { className, field, isLast } = this.props;
|
const { className, field, isLast } = this.props;
|
||||||
const { name, expanded, deprecated, required, kind } = field;
|
const { name, expanded, deprecated, required, kind } = field;
|
||||||
|
@ -53,12 +59,12 @@ export class Field extends React.Component<FieldProps> {
|
||||||
{required && <RequiredLabel> required </RequiredLabel>}
|
{required && <RequiredLabel> required </RequiredLabel>}
|
||||||
</ClickablePropertyNameCell>
|
</ClickablePropertyNameCell>
|
||||||
) : (
|
) : (
|
||||||
<PropertyNameCell className={deprecated ? 'deprecated' : undefined} kind={kind} title={name}>
|
<PropertyNameCell className={deprecated ? 'deprecated' : undefined} kind={kind} title={name}>
|
||||||
<PropertyBullet />
|
<PropertyBullet />
|
||||||
{name}
|
{name}
|
||||||
{required && <RequiredLabel> required </RequiredLabel>}
|
{required && <RequiredLabel> required </RequiredLabel>}
|
||||||
</PropertyNameCell>
|
</PropertyNameCell>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -67,6 +73,9 @@ export class Field extends React.Component<FieldProps> {
|
||||||
<PropertyDetailsCell>
|
<PropertyDetailsCell>
|
||||||
<FieldDetails {...this.props} />
|
<FieldDetails {...this.props} />
|
||||||
</PropertyDetailsCell>
|
</PropertyDetailsCell>
|
||||||
|
{field && field.in === 'path' &&
|
||||||
|
<td><TextField placeholder={field.name} onChange={this.onFieldChange} /></td>
|
||||||
|
}
|
||||||
</tr>
|
</tr>
|
||||||
{field.expanded && withSubSchema && (
|
{field.expanded && withSubSchema && (
|
||||||
<tr key={field.name + 'inner'}>
|
<tr key={field.name + 'inner'}>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { MarkdownRenderer } from '../../services';
|
import { MarkdownRenderer } from '../../services';
|
||||||
|
import styled from '../../styled-components';
|
||||||
import { SanitizedMarkdownHTML } from './SanitizedMdBlock';
|
import { SanitizedMarkdownHTML } from './SanitizedMdBlock';
|
||||||
|
|
||||||
export interface StylingMarkdownProps {
|
export interface StylingMarkdownProps {
|
||||||
|
@ -17,19 +18,31 @@ export type MarkdownProps = BaseMarkdownProps &
|
||||||
StylingMarkdownProps & {
|
StylingMarkdownProps & {
|
||||||
source: string;
|
source: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onSelectUrl?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Markdown extends React.Component<MarkdownProps> {
|
export class Markdown extends React.Component<MarkdownProps> {
|
||||||
|
handleClick = () => {
|
||||||
|
this.props.onSelectUrl();
|
||||||
|
};
|
||||||
render() {
|
render() {
|
||||||
const { source, inline, compact, className } = this.props;
|
const { source, inline, compact, className } = this.props;
|
||||||
const renderer = new MarkdownRenderer();
|
const renderer = new MarkdownRenderer();
|
||||||
return (
|
return (
|
||||||
<SanitizedMarkdownHTML
|
<MarkWrapper onClick={this.handleClick}>
|
||||||
html={renderer.renderMd(source)}
|
<SanitizedMarkdownHTML
|
||||||
inline={inline}
|
html={renderer.renderMd(source)}
|
||||||
compact={compact}
|
inline={inline}
|
||||||
className={className}
|
compact={compact}
|
||||||
/>
|
className={className}
|
||||||
|
/>
|
||||||
|
</MarkWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const MarkWrapper = styled.div`
|
||||||
|
div {
|
||||||
|
width: 100% !important;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { SecurityRequirements } from '../SecurityRequirement/SecurityRequirement';
|
|
||||||
|
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
import { Badge, DarkRightPanel, H2, MiddlePanel, Row } from '../../common-elements';
|
import { Badge, DarkRightPanel, H2, MiddlePanel, Row } from '../../common-elements';
|
||||||
|
|
||||||
import { OptionsContext } from '../OptionsProvider';
|
|
||||||
|
|
||||||
import { ShareLink } from '../../common-elements/linkify';
|
import { ShareLink } from '../../common-elements/linkify';
|
||||||
|
|
||||||
|
import { OperationModel as OperationType, SecuritySchemesModel } from '../../services/models';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
import { ConsoleViewer } from '../Console/ConsoleViewer';
|
||||||
import { Endpoint } from '../Endpoint/Endpoint';
|
import { Endpoint } from '../Endpoint/Endpoint';
|
||||||
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
|
||||||
import { Parameters } from '../Parameters/Parameters';
|
|
||||||
import { RequestSamples } from '../RequestSamples/RequestSamples';
|
|
||||||
import { ResponsesList } from '../Responses/ResponsesList';
|
|
||||||
import { ResponseSamples } from '../ResponseSamples/ResponseSamples';
|
|
||||||
|
|
||||||
import { OperationModel as OperationType } from '../../services/models';
|
|
||||||
import styled from '../../styled-components';
|
|
||||||
import { Extensions } from '../Fields/Extensions';
|
import { Extensions } from '../Fields/Extensions';
|
||||||
|
import { Markdown } from '../Markdown/Markdown';
|
||||||
|
|
||||||
|
import {SwitchBox} from '../../common-elements/SwitchBox';
|
||||||
|
import {OptionsContext } from '../OptionsProvider';
|
||||||
|
import {Parameters } from '../Parameters/Parameters';
|
||||||
|
import {RequestSamples } from '../RequestSamples/RequestSamples';
|
||||||
|
import {ResponsesList } from '../Responses/ResponsesList';
|
||||||
|
import {ResponseSamples } from '../ResponseSamples/ResponseSamples';
|
||||||
|
import {SecurityRequirements } from '../SecurityRequirement/SecurityRequirement';
|
||||||
|
|
||||||
const OperationRow = styled(Row)`
|
const OperationRow = styled(Row)`
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
|
@ -33,12 +34,34 @@ const Description = styled.div`
|
||||||
|
|
||||||
export interface OperationProps {
|
export interface OperationProps {
|
||||||
operation: OperationType;
|
operation: OperationType;
|
||||||
|
securitySchemes: SecuritySchemesModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperationState {
|
||||||
|
executeMode: boolean;
|
||||||
|
urlIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Operation extends React.Component<OperationProps> {
|
export class Operation extends React.Component<OperationProps, OperationState> {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
executeMode: false,
|
||||||
|
urlIndex: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onConsoleClick = () => {
|
||||||
|
this.setState({
|
||||||
|
executeMode: !this.state.executeMode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { operation } = this.props;
|
const { operation, securitySchemes } = this.props;
|
||||||
|
const { executeMode, urlIndex } = this.state;
|
||||||
|
|
||||||
const { name: summary, description, deprecated, externalDocs } = operation;
|
const { name: summary, description, deprecated, externalDocs } = operation;
|
||||||
const hasDescription = !!(description || externalDocs);
|
const hasDescription = !!(description || externalDocs);
|
||||||
|
@ -52,7 +75,14 @@ export class Operation extends React.Component<OperationProps> {
|
||||||
<ShareLink to={operation.id} />
|
<ShareLink to={operation.id} />
|
||||||
{summary} {deprecated && <Badge type="warning"> Deprecated </Badge>}
|
{summary} {deprecated && <Badge type="warning"> Deprecated </Badge>}
|
||||||
</H2>
|
</H2>
|
||||||
{options.pathInMiddlePanel && <Endpoint operation={operation} inverted={true} />}
|
{options.enableConsole &&
|
||||||
|
<SwitchBox
|
||||||
|
onClick={this.onConsoleClick}
|
||||||
|
checked={this.state.executeMode}
|
||||||
|
label="Try it out!"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{options.pathInMiddlePanel && <Endpoint operation={operation} inverted={true} handleUrl={this.onUrlChanged}/>}
|
||||||
{hasDescription && (
|
{hasDescription && (
|
||||||
<Description>
|
<Description>
|
||||||
{description !== undefined && <Markdown source={description} />}
|
{description !== undefined && <Markdown source={description} />}
|
||||||
|
@ -65,13 +95,34 @@ export class Operation extends React.Component<OperationProps> {
|
||||||
<ResponsesList responses={operation.responses} />
|
<ResponsesList responses={operation.responses} />
|
||||||
</MiddlePanel>
|
</MiddlePanel>
|
||||||
<DarkRightPanel>
|
<DarkRightPanel>
|
||||||
{!options.pathInMiddlePanel && <Endpoint operation={operation} />}
|
{!options.pathInMiddlePanel && <Endpoint operation={operation} handleUrl={this.onUrlChanged}/>}
|
||||||
<RequestSamples operation={operation} />
|
{executeMode &&
|
||||||
<ResponseSamples operation={operation} />
|
<div>
|
||||||
|
<ConsoleViewer
|
||||||
|
securitySchemes={securitySchemes}
|
||||||
|
operation={operation}
|
||||||
|
urlIndex={urlIndex}
|
||||||
|
additionalHeaders={options.additionalHeaders}
|
||||||
|
queryParamPrefix={options.queryParamPrefix}
|
||||||
|
queryParamSuffix={options.queryParamSuffix}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{!executeMode &&
|
||||||
|
<RequestSamples operation={operation} />
|
||||||
|
}
|
||||||
|
{!executeMode &&
|
||||||
|
<ResponseSamples operation={operation} />
|
||||||
|
}
|
||||||
</DarkRightPanel>
|
</DarkRightPanel>
|
||||||
</OperationRow>
|
</OperationRow>
|
||||||
)}
|
)}
|
||||||
</OptionsContext.Consumer>
|
</OptionsContext.Consumer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
onUrlChanged = (index= 0) => {
|
||||||
|
this.setState({
|
||||||
|
urlIndex: index,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class Redoc extends React.Component<RedocProps> {
|
||||||
</StickyResponsiveSidebar>
|
</StickyResponsiveSidebar>
|
||||||
<ApiContentWrap className="api-content">
|
<ApiContentWrap className="api-content">
|
||||||
<ApiInfo store={store} />
|
<ApiInfo store={store} />
|
||||||
<ContentItems items={menu.items as any} />
|
<ContentItems store={store} items={menu.items as any} />
|
||||||
</ApiContentWrap>
|
</ApiContentWrap>
|
||||||
<BackgroundStub />
|
<BackgroundStub />
|
||||||
</RedocWrap>
|
</RedocWrap>
|
||||||
|
|
|
@ -44,9 +44,7 @@ export class Schema extends React.Component<Partial<SchemaProps>> {
|
||||||
if (discriminatorProp !== undefined) {
|
if (discriminatorProp !== undefined) {
|
||||||
if (!oneOf || !oneOf.length) {
|
if (!oneOf || !oneOf.length) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Looks like you are using discriminator wrong: you don't have any definition inherited from the ${
|
`Looks like you are using discriminator wrong: you don't have any definition inherited from the ${schema.title}`,
|
||||||
schema.title
|
|
||||||
}`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@ -66,9 +64,9 @@ export class Schema extends React.Component<Partial<SchemaProps>> {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'object':
|
case 'object':
|
||||||
return <ObjectSchema {...this.props as any} />;
|
return <ObjectSchema {...(this.props as any)} />;
|
||||||
case 'array':
|
case 'array':
|
||||||
return <ArraySchema {...this.props as any} />;
|
return <ArraySchema {...(this.props as any)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe adjust FieldDetails to accept schema
|
// TODO: maybe adjust FieldDetails to accept schema
|
||||||
|
|
|
@ -67,18 +67,16 @@ export class SecurityRequirement extends React.PureComponent<SecurityRequirement
|
||||||
const security = this.props.security;
|
const security = this.props.security;
|
||||||
return (
|
return (
|
||||||
<SecurityRequirementOrWrap>
|
<SecurityRequirementOrWrap>
|
||||||
{security.schemes.map(scheme => {
|
{security.schemes.map(scheme => (
|
||||||
return (
|
<SecurityRequirementAndWrap key={scheme.id}>
|
||||||
<SecurityRequirementAndWrap key={scheme.id}>
|
<Link to={scheme.sectionId}>{scheme.id}</Link>
|
||||||
<Link to={scheme.sectionId}>{scheme.id}</Link>
|
{scheme.scopes.length > 0 && ' ('}
|
||||||
{scheme.scopes.length > 0 && ' ('}
|
{scheme.scopes.map(scope => (
|
||||||
{scheme.scopes.map(scope => (
|
<ScopeName key={scope}>{scope}</ScopeName>
|
||||||
<ScopeName key={scope}>{scope}</ScopeName>
|
))}
|
||||||
))}
|
{scheme.scopes.length > 0 && ') '}
|
||||||
{scheme.scopes.length > 0 && ') '}
|
</SecurityRequirementAndWrap>
|
||||||
</SecurityRequirementAndWrap>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</SecurityRequirementOrWrap>
|
</SecurityRequirementOrWrap>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { TokenGroup } from '..';
|
||||||
|
|
||||||
|
import { DarkRightPanel, H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
||||||
|
|
||||||
import { SecuritySchemesModel } from '../../services/models';
|
import { SecuritySchemesModel } from '../../services/models';
|
||||||
|
|
||||||
import { H2, MiddlePanel, Row, Section, ShareLink } from '../../common-elements';
|
|
||||||
import { OpenAPISecurityScheme } from '../../types';
|
import { OpenAPISecurityScheme } from '../../types';
|
||||||
import { titleize } from '../../utils/helpers';
|
import { titleize } from '../../utils/helpers';
|
||||||
import { Markdown } from '../Markdown/Markdown';
|
import { Markdown } from '../Markdown/Markdown';
|
||||||
|
@ -18,11 +20,12 @@ const AUTH_TYPES = {
|
||||||
export interface OAuthFlowProps {
|
export interface OAuthFlowProps {
|
||||||
type: string;
|
type: string;
|
||||||
flow: OpenAPISecurityScheme['flows'][keyof OpenAPISecurityScheme['flows']];
|
flow: OpenAPISecurityScheme['flows'][keyof OpenAPISecurityScheme['flows']];
|
||||||
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OAuthFlow extends React.PureComponent<OAuthFlowProps> {
|
export class OAuthFlow extends React.PureComponent<OAuthFlowProps> {
|
||||||
render() {
|
render() {
|
||||||
const { type, flow } = this.props;
|
const { type, flow, token } = this.props;
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<th> {type} OAuth Flow </th>
|
<th> {type} OAuth Flow </th>
|
||||||
|
@ -49,13 +52,14 @@ export class OAuthFlow extends React.PureComponent<OAuthFlowProps> {
|
||||||
<strong> Scopes: </strong>
|
<strong> Scopes: </strong>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
{Object.keys(flow!.scopes).map(scope => (
|
{Object.keys(flow!.scopes || {}).map(scope => (
|
||||||
<li key={scope}>
|
<li key={scope}>
|
||||||
<code>{scope}</code> - <Markdown inline={true} source={flow!.scopes[scope] || ''} />
|
<code>{scope}</code> - <Markdown inline={true} source={flow!.scopes[scope] || ''} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
<td> {token} </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +69,31 @@ export interface SecurityDefsProps {
|
||||||
securitySchemes: SecuritySchemesModel;
|
securitySchemes: SecuritySchemesModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
|
export interface SecurityDefsState {
|
||||||
|
tokens: Dict<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class SecurityDefs extends React.PureComponent<SecurityDefsProps, SecurityDefsState> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
tokens: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
mutateToken = (scheme, id) => {
|
||||||
|
return () => {
|
||||||
|
scheme.setToken(this.state.tokens[id]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
setToken = id => {
|
||||||
|
return token => {
|
||||||
|
const tokens = this.state.tokens;
|
||||||
|
tokens[id] = token;
|
||||||
|
this.setState({tokens});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.props.securitySchemes.schemes.map(scheme => (
|
return this.props.securitySchemes.schemes.map(scheme => (
|
||||||
<Section id={scheme.sectionId} key={scheme.id}>
|
<Section id={scheme.sectionId} key={scheme.id}>
|
||||||
|
@ -82,22 +110,26 @@ export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
|
||||||
<tr>
|
<tr>
|
||||||
<th> Security scheme type: </th>
|
<th> Security scheme type: </th>
|
||||||
<td> {AUTH_TYPES[scheme.type] || scheme.type} </td>
|
<td> {AUTH_TYPES[scheme.type] || scheme.type} </td>
|
||||||
|
<td> Value </td>
|
||||||
</tr>
|
</tr>
|
||||||
{scheme.apiKey ? (
|
{scheme.apiKey ? (
|
||||||
<tr>
|
<tr>
|
||||||
<th> {titleize(scheme.apiKey.in || '')} parameter name:</th>
|
<th> {titleize(scheme.apiKey.in || '')} parameter name:</th>
|
||||||
<td> {scheme.apiKey.name} </td>
|
<td> {scheme.apiKey.name} </td>
|
||||||
|
<td> {scheme.token} </td>
|
||||||
</tr>
|
</tr>
|
||||||
) : scheme.http ? (
|
) : scheme.http ? (
|
||||||
[
|
[
|
||||||
<tr key="scheme">
|
<tr key="scheme">
|
||||||
<th> HTTP Authorization Scheme </th>
|
<th> HTTP Authorization Scheme </th>
|
||||||
<td> {scheme.http.scheme} </td>
|
<td> {scheme.http.scheme} </td>
|
||||||
|
<td> {scheme.token} </td>
|
||||||
</tr>,
|
</tr>,
|
||||||
scheme.http.scheme === 'bearer' && scheme.http.bearerFormat && (
|
scheme.http.scheme === 'bearer' && scheme.http.bearerFormat && (
|
||||||
<tr key="bearer">
|
<tr key="bearer">
|
||||||
<th> Bearer format </th>
|
<th> Bearer format </th>
|
||||||
<td> "{scheme.http.bearerFormat}" </td>
|
<td> "{scheme.http.bearerFormat}" </td>
|
||||||
|
<td> {scheme.token} </td>
|
||||||
</tr>
|
</tr>
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -109,16 +141,25 @@ export class SecurityDefs extends React.PureComponent<SecurityDefsProps> {
|
||||||
{scheme.openId.connectUrl}
|
{scheme.openId.connectUrl}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td> {scheme.token} </td>
|
||||||
</tr>
|
</tr>
|
||||||
) : scheme.flows ? (
|
) : scheme.flows ? (
|
||||||
Object.keys(scheme.flows).map(type => (
|
Object.keys(scheme.flows).map(type => (
|
||||||
<OAuthFlow key={type} type={type} flow={scheme.flows[type]} />
|
<OAuthFlow key={type} type={type} token={scheme.token} flow={scheme.flows[type]} />
|
||||||
))
|
))
|
||||||
) : null}
|
) : null}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</StyledMarkdownBlock>
|
</StyledMarkdownBlock>
|
||||||
</MiddlePanel>
|
</MiddlePanel>
|
||||||
|
<DarkRightPanel>
|
||||||
|
<TokenGroup
|
||||||
|
title={'Enter ' + scheme.id}
|
||||||
|
description={'You can add token here and store it to use in your request calls in this page.'}
|
||||||
|
onChange={this.setToken(scheme.sectionId)}
|
||||||
|
onSubmit={this.mutateToken(scheme, scheme.sectionId)}
|
||||||
|
/>
|
||||||
|
</DarkRightPanel>
|
||||||
</Row>
|
</Row>
|
||||||
</Section>
|
</Section>
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ClipboardService } from '../../services';
|
import { ClipboardService } from '../../services';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
export class SelectOnClick extends React.PureComponent {
|
interface SelectOnClickProps {
|
||||||
|
onSelectUrl: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SelectOnClick extends React.PureComponent<SelectOnClickProps> {
|
||||||
private child: HTMLDivElement | null;
|
private child: HTMLDivElement | null;
|
||||||
handleClick = () => {
|
handleClick = () => {
|
||||||
ClipboardService.selectElement(this.child);
|
ClipboardService.selectElement(this.child);
|
||||||
|
this.props.onSelectUrl();
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
return (
|
return (
|
||||||
<div ref={el => (this.child = el)} onClick={this.handleClick}>
|
<SelectArea ref={el => (this.child = el)} onClick={this.handleClick.bind(this, children)}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</SelectArea>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const SelectArea = styled.div`
|
||||||
|
width: 80%;
|
||||||
|
`;
|
||||||
|
|
|
@ -19,6 +19,10 @@ export interface StickySidebarProps {
|
||||||
menu: MenuStore;
|
menu: MenuStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface StickySidebarState {
|
||||||
|
offsetTop?: string;
|
||||||
|
}
|
||||||
|
|
||||||
const stickyfill = Stickyfill && Stickyfill();
|
const stickyfill = Stickyfill && Stickyfill();
|
||||||
|
|
||||||
const StyledStickySidebar = styled.div<{ open?: boolean }>`
|
const StyledStickySidebar = styled.div<{ open?: boolean }>`
|
||||||
|
@ -77,13 +81,26 @@ const FloatingButton = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class StickyResponsiveSidebar extends React.Component<StickySidebarProps> {
|
export class StickyResponsiveSidebar extends React.Component<
|
||||||
|
StickySidebarProps,
|
||||||
|
StickySidebarState
|
||||||
|
> {
|
||||||
|
static contextType = OptionsContext;
|
||||||
|
context!: React.ContextType<typeof OptionsContext>;
|
||||||
|
state: StickySidebarState = { offsetTop: '0px' };
|
||||||
|
|
||||||
stickyElement: Element;
|
stickyElement: Element;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (stickyfill) {
|
if (stickyfill) {
|
||||||
stickyfill.add(this.stickyElement);
|
stickyfill.add(this.stickyElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rerender when hydrating from SSR
|
||||||
|
// see https://github.com/facebook/react/issues/8017#issuecomment-256351955
|
||||||
|
this.setState({
|
||||||
|
offsetTop: this.getScrollYOffset(this.context),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -92,7 +109,7 @@ export class StickyResponsiveSidebar extends React.Component<StickySidebarProps>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getScrollYOffset(options) {
|
getScrollYOffset(options: RedocNormalizedOptions) {
|
||||||
let top;
|
let top;
|
||||||
if (this.props.scrollYOffset !== undefined) {
|
if (this.props.scrollYOffset !== undefined) {
|
||||||
top = RedocNormalizedOptions.normalizeScrollYOffset(this.props.scrollYOffset)();
|
top = RedocNormalizedOptions.normalizeScrollYOffset(this.props.scrollYOffset)();
|
||||||
|
@ -105,43 +122,32 @@ export class StickyResponsiveSidebar extends React.Component<StickySidebarProps>
|
||||||
render() {
|
render() {
|
||||||
const open = this.props.menu.sideBarOpened;
|
const open = this.props.menu.sideBarOpened;
|
||||||
|
|
||||||
const style = options => {
|
const top = this.state.offsetTop;
|
||||||
const top = this.getScrollYOffset(options);
|
|
||||||
return {
|
|
||||||
top,
|
|
||||||
height: `calc(100vh - ${top})`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OptionsContext.Consumer>
|
<>
|
||||||
{options => (
|
<StyledStickySidebar
|
||||||
<>
|
open={open}
|
||||||
<StyledStickySidebar
|
className={this.props.className}
|
||||||
open={open}
|
style={{
|
||||||
className={this.props.className}
|
top,
|
||||||
style={style(options)}
|
height: `calc(100vh - ${top})`,
|
||||||
// tslint:disable-next-line
|
}}
|
||||||
ref={el => {
|
// tslint:disable-next-line
|
||||||
this.stickyElement = el as any;
|
ref={el => {
|
||||||
}}
|
this.stickyElement = el as any;
|
||||||
>
|
}}
|
||||||
{this.props.children}
|
>
|
||||||
</StyledStickySidebar>
|
{this.props.children}
|
||||||
<FloatingButton onClick={this.toggleNavMenu}>
|
</StyledStickySidebar>
|
||||||
<AnimatedChevronButton open={open} />
|
<FloatingButton onClick={this.toggleNavMenu}>
|
||||||
</FloatingButton>
|
<AnimatedChevronButton open={open} />
|
||||||
</>
|
</FloatingButton>
|
||||||
)}
|
</>
|
||||||
</OptionsContext.Consumer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleNavMenu = () => {
|
private toggleNavMenu = () => {
|
||||||
this.props.menu.toggleSidebar();
|
this.props.menu.toggleSidebar();
|
||||||
};
|
};
|
||||||
|
|
||||||
// private closeNavMenu = () => {
|
|
||||||
// this.setState({ open: false });
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
84
src/components/TokenGroup/TokenGroup.tsx
Normal file
84
src/components/TokenGroup/TokenGroup.tsx
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Button, RightPanelHeader} from '../../common-elements';
|
||||||
|
import styled from '../../styled-components';
|
||||||
|
|
||||||
|
const SaveTokenButton = styled(Button)`
|
||||||
|
padding: 10px 30px;
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
margin: 0
|
||||||
|
min-width: 60px;
|
||||||
|
max-width: 100px;
|
||||||
|
font-weight: bold;
|
||||||
|
flex: 1 1;
|
||||||
|
order: 2;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TokenTextField = styled.input`
|
||||||
|
padding: 10px 30px 10px 20px;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
background-color: ${props => props.theme.codeSample.backgroundColor};
|
||||||
|
color: ${props => props.theme.codeSample.textColor}
|
||||||
|
white-space: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
direction: ltr;
|
||||||
|
min-width: 300px;
|
||||||
|
flex: 4 1;
|
||||||
|
order: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TokenGroupContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: flex-start;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Description = styled.p`
|
||||||
|
color: white;
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface TokenGroupProps {
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
onSubmit: () => void;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TokenGroup extends React.PureComponent<TokenGroupProps> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.submit = this.submit.bind(this);
|
||||||
|
this.change = this.change.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
this.props.onSubmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
change(e) {
|
||||||
|
this.props.onChange(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RightPanelHeader>
|
||||||
|
{this.props.title}
|
||||||
|
</RightPanelHeader>
|
||||||
|
<TokenGroupContainer>
|
||||||
|
<TokenTextField onChange={this.change} />
|
||||||
|
<SaveTokenButton onClick={this.submit}>Save</SaveTokenButton>
|
||||||
|
</TokenGroupContainer>
|
||||||
|
<Description>
|
||||||
|
{this.props.description}
|
||||||
|
</Description>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat
|
||||||
<Field
|
<Field
|
||||||
field={
|
field={
|
||||||
FieldModel {
|
FieldModel {
|
||||||
|
"$value": "",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"description": "",
|
"description": "",
|
||||||
"example": undefined,
|
"example": undefined,
|
||||||
|
@ -56,6 +57,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat
|
||||||
<Field
|
<Field
|
||||||
field={
|
field={
|
||||||
FieldModel {
|
FieldModel {
|
||||||
|
"$value": "",
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"description": "",
|
"description": "",
|
||||||
"example": undefined,
|
"example": undefined,
|
||||||
|
|
|
@ -30,3 +30,4 @@ export * from './StickySidebar/StickyResponsiveSidebar';
|
||||||
export * from './SearchBox/SearchBox';
|
export * from './SearchBox/SearchBox';
|
||||||
export * from './SchemaDefinition/SchemaDefinition';
|
export * from './SchemaDefinition/SchemaDefinition';
|
||||||
export * from './SourceCode/SourceCode';
|
export * from './SourceCode/SourceCode';
|
||||||
|
export * from './TokenGroup/TokenGroup';
|
||||||
|
|
|
@ -116,7 +116,7 @@ export class MenuStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isScrolledDown) {
|
if (isScrolledDown) {
|
||||||
const el = this.getElementAt(itemIdx + 1);
|
const el = this.getElementAtOrFirstChild(itemIdx + 1);
|
||||||
if (this.scroll.isElementBellow(el)) {
|
if (this.scroll.isElementBellow(el)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,18 @@ export class MenuStore {
|
||||||
return (item && querySelector(`[${SECTION_ATTR}="${item.id}"]`)) || null;
|
return (item && querySelector(`[${SECTION_ATTR}="${item.id}"]`)) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get section/operation DOM Node related to the item or if it is group item, returns first item of the group
|
||||||
|
* @param idx item absolute index
|
||||||
|
*/
|
||||||
|
getElementAtOrFirstChild(idx: number): Element | null {
|
||||||
|
let item = this.flatItems[idx];
|
||||||
|
if (item && item.type === 'group') {
|
||||||
|
item = item.items[0];
|
||||||
|
}
|
||||||
|
return (item && querySelector(`[${SECTION_ATTR}="${item.id}"]`)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* current active item
|
* current active item
|
||||||
*/
|
*/
|
||||||
|
@ -189,6 +201,11 @@ export class MenuStore {
|
||||||
if ((this.activeItem && this.activeItem.id) === (item && item.id)) {
|
if ((this.activeItem && this.activeItem.id) === (item && item.id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item && item.type === 'group') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.deactivate(this.activeItem);
|
this.deactivate(this.activeItem);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
this.history.replace('', rewriteHistory);
|
this.history.replace('', rewriteHistory);
|
||||||
|
|
|
@ -4,7 +4,11 @@ import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types';
|
||||||
|
|
||||||
import { appendToMdHeading, IS_BROWSER } from '../utils/';
|
import { appendToMdHeading, IS_BROWSER } from '../utils/';
|
||||||
import { JsonPointer } from '../utils/JsonPointer';
|
import { JsonPointer } from '../utils/JsonPointer';
|
||||||
import { isNamedDefinition, SECURITY_DEFINITIONS_COMPONENT_NAME } from '../utils/openapi';
|
import {
|
||||||
|
isNamedDefinition,
|
||||||
|
SECURITY_DEFINITIONS_COMPONENT_NAME,
|
||||||
|
SECURITY_DEFINITIONS_JSX_NAME,
|
||||||
|
} from '../utils/openapi';
|
||||||
import { buildComponentComment, MarkdownRenderer } from './MarkdownRenderer';
|
import { buildComponentComment, MarkdownRenderer } from './MarkdownRenderer';
|
||||||
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
import { RedocNormalizedOptions } from './RedocNormalizedOptions';
|
||||||
|
|
||||||
|
@ -40,6 +44,7 @@ class RefCounter {
|
||||||
export class OpenAPIParser {
|
export class OpenAPIParser {
|
||||||
specUrl?: string;
|
specUrl?: string;
|
||||||
spec: OpenAPISpec;
|
spec: OpenAPISpec;
|
||||||
|
mergeRefs: Set<string>;
|
||||||
|
|
||||||
private _refCounter: RefCounter = new RefCounter();
|
private _refCounter: RefCounter = new RefCounter();
|
||||||
|
|
||||||
|
@ -53,6 +58,8 @@ export class OpenAPIParser {
|
||||||
|
|
||||||
this.spec = spec;
|
this.spec = spec;
|
||||||
|
|
||||||
|
this.mergeRefs = new Set();
|
||||||
|
|
||||||
const href = IS_BROWSER ? window.location.href : '';
|
const href = IS_BROWSER ? window.location.href : '';
|
||||||
if (typeof specUrl === 'string') {
|
if (typeof specUrl === 'string') {
|
||||||
this.specUrl = urlResolve(href, specUrl);
|
this.specUrl = urlResolve(href, specUrl);
|
||||||
|
@ -74,7 +81,10 @@ export class OpenAPIParser {
|
||||||
) {
|
) {
|
||||||
// Automatically inject Authentication section with SecurityDefinitions component
|
// Automatically inject Authentication section with SecurityDefinitions component
|
||||||
const description = spec.info.description || '';
|
const description = spec.info.description || '';
|
||||||
if (!MarkdownRenderer.containsComponent(description, SECURITY_DEFINITIONS_COMPONENT_NAME)) {
|
if (
|
||||||
|
!MarkdownRenderer.containsComponent(description, SECURITY_DEFINITIONS_COMPONENT_NAME) &&
|
||||||
|
!MarkdownRenderer.containsComponent(description, SECURITY_DEFINITIONS_JSX_NAME)
|
||||||
|
) {
|
||||||
const comment = buildComponentComment(SECURITY_DEFINITIONS_COMPONENT_NAME);
|
const comment = buildComponentComment(SECURITY_DEFINITIONS_COMPONENT_NAME);
|
||||||
spec.info.description = appendToMdHeading(description, 'Authentication', comment);
|
spec.info.description = appendToMdHeading(description, 'Authentication', comment);
|
||||||
}
|
}
|
||||||
|
@ -176,7 +186,12 @@ export class OpenAPIParser {
|
||||||
schema: OpenAPISchema,
|
schema: OpenAPISchema,
|
||||||
$ref?: string,
|
$ref?: string,
|
||||||
forceCircular: boolean = false,
|
forceCircular: boolean = false,
|
||||||
|
used$Refs = new Set<string>(),
|
||||||
): MergedOpenAPISchema {
|
): MergedOpenAPISchema {
|
||||||
|
if ($ref) {
|
||||||
|
used$Refs.add($ref);
|
||||||
|
}
|
||||||
|
|
||||||
schema = this.hoistOneOfs(schema);
|
schema = this.hoistOneOfs(schema);
|
||||||
|
|
||||||
if (schema.allOf === undefined) {
|
if (schema.allOf === undefined) {
|
||||||
|
@ -198,16 +213,25 @@ export class OpenAPIParser {
|
||||||
receiver.items = { ...receiver.items };
|
receiver.items = { ...receiver.items };
|
||||||
}
|
}
|
||||||
|
|
||||||
const allOfSchemas = schema.allOf.map(subSchema => {
|
const allOfSchemas = schema.allOf
|
||||||
const resolved = this.deref(subSchema, forceCircular);
|
.map(subSchema => {
|
||||||
const subRef = subSchema.$ref || undefined;
|
if (subSchema && subSchema.$ref && used$Refs.has(subSchema.$ref)) {
|
||||||
const subMerged = this.mergeAllOf(resolved, subRef, forceCircular);
|
return undefined;
|
||||||
receiver.parentRefs!.push(...(subMerged.parentRefs || []));
|
}
|
||||||
return {
|
|
||||||
$ref: subRef,
|
const resolved = this.deref(subSchema, forceCircular);
|
||||||
schema: subMerged,
|
const subRef = subSchema.$ref || undefined;
|
||||||
};
|
const subMerged = this.mergeAllOf(resolved, subRef, forceCircular, used$Refs);
|
||||||
});
|
receiver.parentRefs!.push(...(subMerged.parentRefs || []));
|
||||||
|
return {
|
||||||
|
$ref: subRef,
|
||||||
|
schema: subMerged,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(child => child !== undefined) as Array<{
|
||||||
|
$ref: string | undefined;
|
||||||
|
schema: MergedOpenAPISchema;
|
||||||
|
}>;
|
||||||
|
|
||||||
for (const { $ref: subSchemaRef, schema: subSchema } of allOfSchemas) {
|
for (const { $ref: subSchemaRef, schema: subSchema } of allOfSchemas) {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -9,6 +9,8 @@ export interface RedocRawOptions {
|
||||||
theme?: ThemeInterface;
|
theme?: ThemeInterface;
|
||||||
scrollYOffset?: number | string | (() => number);
|
scrollYOffset?: number | string | (() => number);
|
||||||
hideHostname?: boolean | string;
|
hideHostname?: boolean | string;
|
||||||
|
enableConsole?: boolean;
|
||||||
|
additionalHeaders?: object;
|
||||||
expandResponses?: string | 'all';
|
expandResponses?: string | 'all';
|
||||||
requiredPropsFirst?: boolean | string;
|
requiredPropsFirst?: boolean | string;
|
||||||
sortPropsAlphabetically?: boolean | string;
|
sortPropsAlphabetically?: boolean | string;
|
||||||
|
@ -25,12 +27,20 @@ export interface RedocRawOptions {
|
||||||
menuToggle?: boolean | string;
|
menuToggle?: boolean | string;
|
||||||
jsonSampleExpandLevel?: number | string | 'all';
|
jsonSampleExpandLevel?: number | string | 'all';
|
||||||
|
|
||||||
|
providedByName?: string;
|
||||||
|
providedByUri?: string;
|
||||||
|
queryParamPrefix?: string;
|
||||||
|
queryParamSuffix?: string;
|
||||||
|
|
||||||
unstable_ignoreMimeParameters?: boolean;
|
unstable_ignoreMimeParameters?: boolean;
|
||||||
|
|
||||||
allowedMdComponents?: Dict<MDXComponentMeta>;
|
allowedMdComponents?: Dict<MDXComponentMeta>;
|
||||||
|
|
||||||
labels?: LabelsConfigRaw;
|
labels?: LabelsConfigRaw;
|
||||||
|
|
||||||
enumSkipQuotes?: boolean | string;
|
enumSkipQuotes?: boolean | string;
|
||||||
|
|
||||||
|
expandDefaultServerVariables?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function argValueToBoolean(val?: string | boolean): boolean {
|
function argValueToBoolean(val?: string | boolean): boolean {
|
||||||
|
@ -141,11 +151,19 @@ export class RedocNormalizedOptions {
|
||||||
menuToggle: boolean;
|
menuToggle: boolean;
|
||||||
jsonSampleExpandLevel: number;
|
jsonSampleExpandLevel: number;
|
||||||
enumSkipQuotes: boolean;
|
enumSkipQuotes: boolean;
|
||||||
|
enableConsole: boolean;
|
||||||
|
additionalHeaders: object;
|
||||||
|
providedByName: string;
|
||||||
|
providedByUri: string;
|
||||||
|
queryParamPrefix: string;
|
||||||
|
queryParamSuffix: string;
|
||||||
|
|
||||||
/* tslint:disable-next-line */
|
/* tslint:disable-next-line */
|
||||||
unstable_ignoreMimeParameters: boolean;
|
unstable_ignoreMimeParameters: boolean;
|
||||||
allowedMdComponents: Dict<MDXComponentMeta>;
|
allowedMdComponents: Dict<MDXComponentMeta>;
|
||||||
|
|
||||||
|
expandDefaultServerVariables: boolean;
|
||||||
|
|
||||||
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
|
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
|
||||||
raw = { ...defaults, ...raw };
|
raw = { ...defaults, ...raw };
|
||||||
const hook = raw.theme && raw.theme.extensionsHook;
|
const hook = raw.theme && raw.theme.extensionsHook;
|
||||||
|
@ -177,9 +195,17 @@ export class RedocNormalizedOptions {
|
||||||
raw.jsonSampleExpandLevel,
|
raw.jsonSampleExpandLevel,
|
||||||
);
|
);
|
||||||
this.enumSkipQuotes = argValueToBoolean(raw.enumSkipQuotes);
|
this.enumSkipQuotes = argValueToBoolean(raw.enumSkipQuotes);
|
||||||
|
this.enableConsole = argValueToBoolean(raw.enableConsole);
|
||||||
|
this.additionalHeaders = raw.additionalHeaders || {};
|
||||||
|
this.providedByName = raw.providedByName || 'Documentation Powered by ReDoc';
|
||||||
|
this.providedByUri = raw.providedByUri || 'https://github.com/Rebilly/ReDoc';
|
||||||
|
this.queryParamPrefix = raw.queryParamPrefix || '{';
|
||||||
|
this.queryParamSuffix = raw.queryParamSuffix || '}';
|
||||||
|
|
||||||
this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters);
|
this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters);
|
||||||
|
|
||||||
this.allowedMdComponents = raw.allowedMdComponents || {};
|
this.allowedMdComponents = raw.allowedMdComponents || {};
|
||||||
|
|
||||||
|
this.expandDefaultServerVariables = argValueToBoolean(raw.expandDefaultServerVariables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ let worker: new () => Worker;
|
||||||
if (IS_BROWSER) {
|
if (IS_BROWSER) {
|
||||||
try {
|
try {
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
worker = require('workerize-loader?inline&fallback=false!./SearchWorker.worker');
|
worker = require('workerize-loader?fallback=false!./SearchWorker.worker');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
worker = require('./SearchWorker.worker').default;
|
worker = require('./SearchWorker.worker').default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,8 @@ function getDefaultStyleValue(parameterLocation: OpenAPIParameterLocation): Open
|
||||||
* Field or Parameter model ready to be used by components
|
* Field or Parameter model ready to be used by components
|
||||||
*/
|
*/
|
||||||
export class FieldModel {
|
export class FieldModel {
|
||||||
@observable
|
@observable expanded: boolean = false;
|
||||||
expanded: boolean = false;
|
@observable $value: string = '';
|
||||||
|
|
||||||
schema: SchemaModel;
|
schema: SchemaModel;
|
||||||
name: string;
|
name: string;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
|
@ -92,4 +91,9 @@ export class FieldModel {
|
||||||
toggle() {
|
toggle() {
|
||||||
this.expanded = !this.expanded;
|
this.expanded = !this.expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setValue(value: string) {
|
||||||
|
this.$value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import {observable} from 'mobx';
|
||||||
import { OpenAPISecurityScheme, Referenced } from '../../types';
|
import { OpenAPISecurityScheme, Referenced } from '../../types';
|
||||||
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi';
|
import { SECURITY_SCHEMES_SECTION_PREFIX } from '../../utils/openapi';
|
||||||
import { OpenAPIParser } from '../OpenAPIParser';
|
import { OpenAPIParser } from '../OpenAPIParser';
|
||||||
|
@ -22,6 +23,9 @@ export class SecuritySchemeModel {
|
||||||
connectUrl: string;
|
connectUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@observable
|
||||||
|
token?: string = '';
|
||||||
|
|
||||||
constructor(parser: OpenAPIParser, id: string, scheme: Referenced<OpenAPISecurityScheme>) {
|
constructor(parser: OpenAPIParser, id: string, scheme: Referenced<OpenAPISecurityScheme>) {
|
||||||
const info = parser.deref(scheme);
|
const info = parser.deref(scheme);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -52,9 +56,14 @@ export class SecuritySchemeModel {
|
||||||
this.flows = info.flows;
|
this.flows = info.flows;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setToken(token: string) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SecuritySchemesModel {
|
export class SecuritySchemesModel {
|
||||||
|
@observable
|
||||||
schemes: SecuritySchemeModel[];
|
schemes: SecuritySchemeModel[];
|
||||||
|
|
||||||
constructor(parser: OpenAPIParser) {
|
constructor(parser: OpenAPIParser) {
|
||||||
|
|
|
@ -149,6 +149,10 @@ const defaultTheme: ThemeInterface = {
|
||||||
},
|
},
|
||||||
codeSample: {
|
codeSample: {
|
||||||
backgroundColor: ({ rightPanel }) => darken(0.1, rightPanel.backgroundColor),
|
backgroundColor: ({ rightPanel }) => darken(0.1, rightPanel.backgroundColor),
|
||||||
|
textColor: ({ rightPanel }) => rightPanel.textColor,
|
||||||
|
},
|
||||||
|
styledPre: {
|
||||||
|
maxHeight: '500px',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -321,9 +325,13 @@ export interface ResolvedThemeInterface {
|
||||||
};
|
};
|
||||||
codeSample: {
|
codeSample: {
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
|
textColor: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
extensionsHook?: (name: string, props: any) => string;
|
extensionsHook?: (name: string, props: any) => string;
|
||||||
|
styledPre: {
|
||||||
|
maxHeight: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type primitive = string | number | boolean | undefined | null;
|
export type primitive = string | number | boolean | undefined | null;
|
||||||
|
|
|
@ -60,7 +60,7 @@ describe('Utils', () => {
|
||||||
test('should behave like Object.assign on the top level', () => {
|
test('should behave like Object.assign on the top level', () => {
|
||||||
const obj1 = { a: { a1: 'A1' }, c: 'C' };
|
const obj1 = { a: { a1: 'A1' }, c: 'C' };
|
||||||
const obj2 = { a: undefined, b: { b1: 'B1' } };
|
const obj2 = { a: undefined, b: { b1: 'B1' } };
|
||||||
expect(mergeObjects({}, obj1, obj2)).toEqual(Object.assign({}, obj1, obj2));
|
expect(mergeObjects({}, obj1, obj2)).toEqual({ ...obj1, ...obj2 });
|
||||||
});
|
});
|
||||||
test('should not merge array values, just override', () => {
|
test('should not merge array values, just override', () => {
|
||||||
const obj1 = { a: ['A', 'B'] };
|
const obj1 = { a: ['A', 'B'] };
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
|
|
||||||
import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
|
import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
|
||||||
import { OpenAPIParameter, OpenAPIParameterLocation, OpenAPIParameterStyle } from '../../types';
|
import { OpenAPIParameter, OpenAPIParameterLocation, OpenAPIParameterStyle } from '../../types';
|
||||||
|
import { expandDefaultServerVariables } from '../openapi';
|
||||||
|
|
||||||
describe('Utils', () => {
|
describe('Utils', () => {
|
||||||
describe('openapi getStatusCode', () => {
|
describe('openapi getStatusCode', () => {
|
||||||
|
@ -293,6 +294,39 @@ describe('Utils', () => {
|
||||||
]);
|
]);
|
||||||
expect(res).toEqual([{ url: 'https://base.com/sandbox/test', description: 'test' }]);
|
expect(res).toEqual([{ url: 'https://base.com/sandbox/test', description: 'test' }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should expand variables', () => {
|
||||||
|
const servers = normalizeServers('', [
|
||||||
|
{
|
||||||
|
url: 'http://{host}{basePath}',
|
||||||
|
variables: {
|
||||||
|
host: {
|
||||||
|
default: '127.0.0.1',
|
||||||
|
},
|
||||||
|
basePath: {
|
||||||
|
default: '/path/to/endpoint',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'http://127.0.0.2:{port}',
|
||||||
|
variables: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'http://127.0.0.3',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(expandDefaultServerVariables(servers[0].url, servers[0].variables)).toEqual(
|
||||||
|
'http://127.0.0.1/path/to/endpoint',
|
||||||
|
);
|
||||||
|
expect(expandDefaultServerVariables(servers[1].url, servers[1].variables)).toEqual(
|
||||||
|
'http://127.0.0.2:{port}',
|
||||||
|
);
|
||||||
|
expect(expandDefaultServerVariables(servers[2].url, servers[2].variables)).toEqual(
|
||||||
|
'http://127.0.0.3',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('openapi humanizeConstraints', () => {
|
describe('openapi humanizeConstraints', () => {
|
||||||
|
@ -404,7 +438,7 @@ describe('Utils', () => {
|
||||||
{ style: 'simple', explode: false, expected: 'role,admin,firstName,Alex' },
|
{ style: 'simple', explode: false, expected: 'role,admin,firstName,Alex' },
|
||||||
{ style: 'simple', explode: true, expected: 'role=admin,firstName=Alex' },
|
{ style: 'simple', explode: true, expected: 'role=admin,firstName=Alex' },
|
||||||
{ style: 'label', explode: false, expected: '.role,admin,firstName,Alex' },
|
{ style: 'label', explode: false, expected: '.role,admin,firstName,Alex' },
|
||||||
{ style: 'label', explode: true, expected: '.role=admin,firstName=Alex' },
|
{ style: 'label', explode: true, expected: '.role=admin.firstName=Alex' },
|
||||||
{ style: 'matrix', explode: false, expected: ';id=role,admin,firstName,Alex' },
|
{ style: 'matrix', explode: false, expected: ';id=role,admin,firstName,Alex' },
|
||||||
{ style: 'matrix', explode: true, expected: ';role=admin;firstName=Alex' },
|
{ style: 'matrix', explode: true, expected: ';role=admin;firstName=Alex' },
|
||||||
],
|
],
|
||||||
|
@ -516,9 +550,7 @@ describe('Utils', () => {
|
||||||
locationTestGroup.cases.forEach(valueTypeTestGroup => {
|
locationTestGroup.cases.forEach(valueTypeTestGroup => {
|
||||||
describe(valueTypeTestGroup.description, () => {
|
describe(valueTypeTestGroup.description, () => {
|
||||||
valueTypeTestGroup.cases.forEach(testCase => {
|
valueTypeTestGroup.cases.forEach(testCase => {
|
||||||
it(`should serialize correctly when style is ${testCase.style} and explode is ${
|
it(`should serialize correctly when style is ${testCase.style} and explode is ${testCase.explode}`, () => {
|
||||||
testCase.explode
|
|
||||||
}`, () => {
|
|
||||||
const parameter: OpenAPIParameter = {
|
const parameter: OpenAPIParameter = {
|
||||||
name: locationTestGroup.name,
|
name: locationTestGroup.name,
|
||||||
in: locationTestGroup.location,
|
in: locationTestGroup.location,
|
||||||
|
|
1
src/utils/fetch.ts
Normal file
1
src/utils/fetch.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
//parseparseFetchFetch
|
|
@ -83,7 +83,7 @@ export function appendToMdHeading(md: string, heading: string, content: string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// credits https://stackoverflow.com/a/46973278/1749888
|
// credits https://stackoverflow.com/a/46973278/1749888
|
||||||
export const mergeObjects = <T extends object = object>(target: T, ...sources: T[]): T => {
|
export const mergeObjects = (target: any, ...sources: any[]): any => {
|
||||||
if (!sources.length) {
|
if (!sources.length) {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,20 @@ export async function loadAndBundleSpec(specUrlOrObject: object | string): Promi
|
||||||
resolve: { http: { withCredentials: false } },
|
resolve: { http: { withCredentials: false } },
|
||||||
} as object)) as any;
|
} as object)) as any;
|
||||||
|
|
||||||
|
let v2Specs = spec;
|
||||||
if (spec.swagger !== undefined) {
|
if (spec.swagger !== undefined) {
|
||||||
return convertSwagger2OpenAPI(spec);
|
v2Specs = await convertSwagger2OpenAPI(spec);
|
||||||
} else {
|
|
||||||
return spec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we can derefrence the schema here for future use.
|
||||||
|
// import { cloneDeep } from 'lodash';
|
||||||
|
// const derefrencedSpec = await parser.dereference(cloneDeep(spec));
|
||||||
|
// const derefed = await parser.dereference(v2Specs, {
|
||||||
|
// resolve: { http: { withCredentials: false } },
|
||||||
|
// } as object);
|
||||||
|
|
||||||
|
return v2Specs;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertSwagger2OpenAPI(spec: any): Promise<OpenAPISpec> {
|
export function convertSwagger2OpenAPI(spec: any): Promise<OpenAPISpec> {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import { URI } from 'uri-template-lite';
|
const URLtemplate = require('url-template');
|
||||||
|
|
||||||
import { OpenAPIParser } from '../services/OpenAPIParser';
|
import { OpenAPIParser } from '../services/OpenAPIParser';
|
||||||
import {
|
import {
|
||||||
|
@ -168,7 +168,7 @@ function serializeFormValue(name: string, explode: boolean, value: any) {
|
||||||
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
|
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
|
||||||
const safeName = '__redoc_param_name__';
|
const safeName = '__redoc_param_name__';
|
||||||
const suffix = explode ? '*' : '';
|
const suffix = explode ? '*' : '';
|
||||||
const template = new URI.Template(`{?${safeName}${suffix}}`);
|
const template = URLtemplate.parse(`{?${safeName}${suffix}}`);
|
||||||
return template
|
return template
|
||||||
.expand({ [safeName]: value })
|
.expand({ [safeName]: value })
|
||||||
.substring(1)
|
.substring(1)
|
||||||
|
@ -227,7 +227,7 @@ function serializePathParameter(
|
||||||
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later
|
// Use RFC6570 safe name ([a-zA-Z0-9_]) and replace with our name later
|
||||||
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
|
// e.g. URI.template doesn't parse names with hypen (-) which are valid query param names
|
||||||
const safeName = '__redoc_param_name__';
|
const safeName = '__redoc_param_name__';
|
||||||
const template = new URI.Template(`{${prefix}${safeName}${suffix}}`);
|
const template = URLtemplate.parse(`{${prefix}${safeName}${suffix}}`);
|
||||||
|
|
||||||
return template.expand({ [safeName]: value }).replace(/__redoc_param_name__/g, name);
|
return template.expand({ [safeName]: value }).replace(/__redoc_param_name__/g, name);
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,7 @@ function serializeQueryParameter(
|
||||||
return `${name}=${value.join('|')}`;
|
return `${name}=${value.join('|')}`;
|
||||||
case 'deepObject':
|
case 'deepObject':
|
||||||
if (!explode || Array.isArray(value) || typeof value !== 'object') {
|
if (!explode || Array.isArray(value) || typeof value !== 'object') {
|
||||||
console.warn('The style deepObject is only applicable for objects with expolde=true');
|
console.warn('The style deepObject is only applicable for objects with explode=true');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ function serializeHeaderParameter(
|
||||||
|
|
||||||
// name is not important here, so use RFC6570 safe name ([a-zA-Z0-9_])
|
// name is not important here, so use RFC6570 safe name ([a-zA-Z0-9_])
|
||||||
const name = '__redoc_param_name__';
|
const name = '__redoc_param_name__';
|
||||||
const template = new URI.Template(`{${name}${suffix}}`);
|
const template = URLtemplate.parse(`{${name}${suffix}}`);
|
||||||
return decodeURIComponent(template.expand({ [name]: value }));
|
return decodeURIComponent(template.expand({ [name]: value }));
|
||||||
default:
|
default:
|
||||||
console.warn('Unexpected style for header: ' + style);
|
console.warn('Unexpected style for header: ' + style);
|
||||||
|
@ -487,6 +487,13 @@ export function mergeSimilarMediaTypes(types: Dict<OpenAPIMediaType>): Dict<Open
|
||||||
return mergedTypes;
|
return mergedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function expandDefaultServerVariables(url: string, variables: object = {}) {
|
||||||
|
return url.replace(
|
||||||
|
/(?:{)(\w+)(?:})/g,
|
||||||
|
(match, name) => (variables[name] && variables[name].default) || match,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function normalizeServers(
|
export function normalizeServers(
|
||||||
specUrl: string | undefined,
|
specUrl: string | undefined,
|
||||||
servers: OpenAPIServer[],
|
servers: OpenAPIServer[],
|
||||||
|
|
|
@ -39,4 +39,4 @@
|
||||||
"./src/**/*.ts?",
|
"./src/**/*.ts?",
|
||||||
"demo/*.tsx"
|
"demo/*.tsx"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
"quotemark": [true, "single", "avoid-template", "jsx-double"],
|
"quotemark": [true, "single", "avoid-template", "jsx-double"],
|
||||||
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
|
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
|
||||||
"arrow-parens": [true, "ban-single-arg-parens"],
|
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||||
"no-submodule-imports": [true, "prismjs", "perfect-scrollbar", "react-dom", "core-js"],
|
"no-submodule-imports": [true, "prismjs", "perfect-scrollbar", "react-dom", "core-js", "brace"],
|
||||||
"object-literal-key-quotes": [true, "as-needed"],
|
"object-literal-key-quotes": [true, "as-needed"],
|
||||||
"no-unused-expression": [true, "allow-tagged-template"],
|
"no-unused-expression": [true, "allow-tagged-template"],
|
||||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||||
|
|
82
yarn.lock
82
yarn.lock
|
@ -570,6 +570,14 @@
|
||||||
"@babel/helper-regex" "^7.4.4"
|
"@babel/helper-regex" "^7.4.4"
|
||||||
regexpu-core "^4.5.4"
|
regexpu-core "^4.5.4"
|
||||||
|
|
||||||
|
"@babel/polyfill@^7.4.4":
|
||||||
|
version "7.8.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.3.tgz#2333fc2144a542a7c07da39502ceeeb3abe4debd"
|
||||||
|
integrity sha512-0QEgn2zkCzqGIkSWWAEmvxD7e00Nm9asTtQvi7HdlYvMhjy/J38V/1Y9ode0zEJeIuxAI0uftiAzqc7nVeWUGg==
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.6.5"
|
||||||
|
regenerator-runtime "^0.13.2"
|
||||||
|
|
||||||
"@babel/preset-env@^7.0.0":
|
"@babel/preset-env@^7.0.0":
|
||||||
version "7.5.5"
|
version "7.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a"
|
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a"
|
||||||
|
@ -1052,11 +1060,21 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.0.tgz#4328c9f65698e59f4feade8f4e5d928c748fd643"
|
resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.0.tgz#4328c9f65698e59f4feade8f4e5d928c748fd643"
|
||||||
integrity sha512-mEyuziLrfDCQ4juQP1k706BUU/c8OGn/ZFl69AXXY6dStHClKX4P+N8+rhqpul1vRDA2VOygzMRSJJZHyDEOfw==
|
integrity sha512-mEyuziLrfDCQ4juQP1k706BUU/c8OGn/ZFl69AXXY6dStHClKX4P+N8+rhqpul1vRDA2VOygzMRSJJZHyDEOfw==
|
||||||
|
|
||||||
|
"@types/promise@^7.1.30":
|
||||||
|
version "7.1.30"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/promise/-/promise-7.1.30.tgz#1b6714b321fdfc54d1527e7a17116a0e1f2ab810"
|
||||||
|
integrity sha1-G2cUsyH9/FTRUn56FxFqDh8quBA=
|
||||||
|
|
||||||
"@types/prop-types@*", "@types/prop-types@^15.7.1":
|
"@types/prop-types@*", "@types/prop-types@^15.7.1":
|
||||||
version "15.7.1"
|
version "15.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6"
|
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6"
|
||||||
integrity sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==
|
integrity sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==
|
||||||
|
|
||||||
|
"@types/qs@^6.5.1":
|
||||||
|
version "6.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.0.tgz#2a5fa918786d07d3725726f7f650527e1cfeaffd"
|
||||||
|
integrity sha512-c4zji5CjWv1tJxIZkz1oUtGcdOlsH3aza28Nqmm+uNDWBRHoMsjooBEN4czZp1V3iXPihE/VRUOBqg+4Xq0W4g==
|
||||||
|
|
||||||
"@types/react-dom@^16.8.5":
|
"@types/react-dom@^16.8.5":
|
||||||
version "16.8.5"
|
version "16.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.5.tgz#3e3f4d99199391a7fb40aa3a155c8dd99b899cbd"
|
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.5.tgz#3e3f4d99199391a7fb40aa3a155c8dd99b899cbd"
|
||||||
|
@ -1459,6 +1477,16 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5, ajv@^6.9.1:
|
||||||
json-schema-traverse "^0.4.1"
|
json-schema-traverse "^0.4.1"
|
||||||
uri-js "^4.2.2"
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
|
ajv@^6.4.0:
|
||||||
|
version "6.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
|
||||||
|
integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal "^3.1.1"
|
||||||
|
fast-json-stable-stringify "^2.0.0"
|
||||||
|
json-schema-traverse "^0.4.1"
|
||||||
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
ansi-colors@^3.0.0:
|
ansi-colors@^3.0.0:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
||||||
|
@ -1953,6 +1981,11 @@ brace-expansion@^1.1.7:
|
||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
concat-map "0.0.1"
|
concat-map "0.0.1"
|
||||||
|
|
||||||
|
brace@^0.11.1:
|
||||||
|
version "0.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58"
|
||||||
|
integrity sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg=
|
||||||
|
|
||||||
braces@^2.3.1, braces@^2.3.2:
|
braces@^2.3.1, braces@^2.3.2:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
|
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
|
||||||
|
@ -2879,6 +2912,11 @@ core-js@^2.5.7:
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
|
||||||
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
|
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
|
||||||
|
|
||||||
|
core-js@^2.6.5:
|
||||||
|
version "2.6.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
|
||||||
|
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
|
||||||
|
|
||||||
core-js@^3.1.4:
|
core-js@^3.1.4:
|
||||||
version "3.1.4"
|
version "3.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
|
||||||
|
@ -3323,6 +3361,11 @@ dezalgo@^1.0.0:
|
||||||
asap "^2.0.0"
|
asap "^2.0.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
|
diff-match-patch@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
|
||||||
|
integrity sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==
|
||||||
|
|
||||||
diff-sequences@^24.3.0:
|
diff-sequences@^24.3.0:
|
||||||
version "24.3.0"
|
version "24.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975"
|
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975"
|
||||||
|
@ -4022,6 +4065,11 @@ fast-deep-equal@^2.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||||
|
|
||||||
|
fast-deep-equal@^3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||||
|
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
|
||||||
|
|
||||||
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
|
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||||
|
@ -6205,6 +6253,11 @@ lodash.flattendeep@^4.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
|
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
|
||||||
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
|
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
|
||||||
|
|
||||||
|
lodash.get@^4.4.2:
|
||||||
|
version "4.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||||
|
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||||
|
|
||||||
lodash.isequal@^4.5.0:
|
lodash.isequal@^4.5.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||||
|
@ -7886,6 +7939,11 @@ qs@6.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
|
||||||
|
qs@^6.5.2:
|
||||||
|
version "6.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9"
|
||||||
|
integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==
|
||||||
|
|
||||||
qs@~6.5.2:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
|
@ -7976,6 +8034,18 @@ rc@^1.2.7:
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-json-comments "~2.0.1"
|
strip-json-comments "~2.0.1"
|
||||||
|
|
||||||
|
react-ace@^6.0.0:
|
||||||
|
version "6.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-6.6.0.tgz#a79457ef03c3b1f8d4fc598a003b1d6ad464f1a0"
|
||||||
|
integrity sha512-Jehhp8bxa8kqiXk07Jzy+uD5qZMBwo43O+raniGHjdX7Qk93xFkKaAz8LxtUVZPJGlRnV5ODMNj0qHwDSN+PBw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/polyfill" "^7.4.4"
|
||||||
|
brace "^0.11.1"
|
||||||
|
diff-match-patch "^1.0.4"
|
||||||
|
lodash.get "^4.4.2"
|
||||||
|
lodash.isequal "^4.5.0"
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
|
||||||
react-dom@^16.8.6:
|
react-dom@^16.8.6:
|
||||||
version "16.8.6"
|
version "16.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
|
||||||
|
@ -8017,6 +8087,13 @@ react-lifecycles-compat@^3.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||||
|
|
||||||
|
react-switch@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-5.0.1.tgz#449277f4c3aed5286fffd0f50d5cbc2a23330406"
|
||||||
|
integrity sha512-Pa5kvqRfX85QUCK1Jv0rxyeElbC3aNpCP5hV0LoJpU/Y6kydf0t4kRriQ6ZYA4kxWwAYk/cH51T4/sPzV9mCgQ==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react-tabs@^3.0.0:
|
react-tabs@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127"
|
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-3.0.0.tgz#60311a17c755eb6aa9b3310123e67db421605127"
|
||||||
|
@ -9846,6 +9923,11 @@ url-polyfill@^1.1.7:
|
||||||
resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.7.tgz#402ee84360eb549bbeb585f4c7971e79a31de9e3"
|
resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.7.tgz#402ee84360eb549bbeb585f4c7971e79a31de9e3"
|
||||||
integrity sha512-ZrAxYWCREjmMtL8gSbSiKKLZZticgihCvVBtrFbUVpyoETt8GQJeG2okMWA8XryDAaHMjJfhnc+rnhXRbI4DXA==
|
integrity sha512-ZrAxYWCREjmMtL8gSbSiKKLZZticgihCvVBtrFbUVpyoETt8GQJeG2okMWA8XryDAaHMjJfhnc+rnhXRbI4DXA==
|
||||||
|
|
||||||
|
url-template@^2.0.8:
|
||||||
|
version "2.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
|
||||||
|
integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE=
|
||||||
|
|
||||||
url@0.11.0, url@^0.11.0:
|
url@0.11.0, url@^0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
|
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user