From b7bc88a32662a0651ce17dbfc02dc36e1bd47a7c Mon Sep 17 00:00:00 2001 From: Mike Ellan <52717970+sonicyeti@users.noreply.github.com> Date: Wed, 22 Jul 2020 09:13:06 -0400 Subject: [PATCH] Design sidebar (#2328) * updated lock file * Rolling sidebar from SB into application * Type fix on the method label output * Update packages/insomnia-components/components/sidebar.js Co-authored-by: Opender Singh * PR Feedback - Keys, useCallback Hook * stubbing component breakout * PR Feedback - Breaking out most UI elements into components - Filter component in place - Various CSS tweaks * Removing unused file * Updating toggle * Resuable sidebar section (#2359) * Introduce resuable sidebar section * Stop eslint complaining * add react-use * Lint fixes * Make the storybook story less wide * Component development Abstracting out line level components i.e. Section > Header > Filter > Panel > Items Various code fixes * Cleaning up section visibility state * Reverting visibiilty state updater * Adding paths on click for spec scrolling * refreshing package-lock to resolve conflict * PR feedback for sidebar components * Update packages/insomnia-components/components/sidebar/sidebar-header.js Co-authored-by: Opender Singh * Including lock * Merge fix * Component structuring, prop clean-up, css updates * Cleaning up components, pr feedback, fixing styling * array index reference clean-up/clarity * Leveraging useToggle rather than manual useState toggling * Cleaning up logs * Hide info section if missing from spec. * Update packages/insomnia-components/components/sidebar/sidebar-responses.js Co-authored-by: Opender Singh * Update packages/insomnia-components/components/sidebar/sidebar-schemas.js Co-authored-by: Opender Singh * Pull fragment * Destructuring and filter cleanup * Clearing filter value and DOM on section collapse * Merge latest * Merge conflict cleanup Co-authored-by: Opender Singh --- .../spec-editor/spec-editor-sidebar.js | 20 +- .../css/components/spec-editor-sidebar.less | 37 - packages/insomnia-app/app/ui/css/index.less | 1 - packages/insomnia-app/package-lock.json | 85 +- packages/insomnia-app/package.json | 1 + packages/insomnia-cli/dist/cli.js | 28 + .../insomnia-cli/dist/commands/generate.js | 82 + .../git-repo-without-insomnia/blank.js | 1 + packages/insomnia-cli/dist/db/mem-db.js | 65 + packages/insomnia-cli/dist/db/types.js | 11 + packages/insomnia-cli/dist/util.js | 47 + .../assets/icn-brackets.svg | 3 + .../insomnia-components/assets/icn-key.svg | 3 + .../insomnia-components/components/sidebar.js | 345 -- .../components/sidebar.stories.js | 20 - .../components/sidebar/index.js | 165 + .../components/sidebar/sidebar-filter.js | 57 + .../components/sidebar/sidebar-header.js | 80 + .../components/sidebar/sidebar-headers.js | 53 + .../components/sidebar/sidebar-info.js | 40 + .../components/sidebar/sidebar-item.js | 84 + .../components/sidebar/sidebar-panel.js | 51 + .../components/sidebar/sidebar-parameters.js | 54 + .../components/sidebar/sidebar-paths.js | 66 + .../components/sidebar/sidebar-requests.js | 88 + .../components/sidebar/sidebar-responses.js | 52 + .../components/sidebar/sidebar-schemas.js | 47 + .../components/sidebar/sidebar-section.js | 59 + .../components/sidebar/sidebar-security.js | 48 + .../components/sidebar/sidebar-servers.js | 48 + .../components/sidebar/sidebar-text-item.js | 32 + .../components/sidebar/sidebar.stories.js | 2960 +++++++++++++++++ .../components/svg-icon.js | 6 + .../flow-typed/react-use.js | 7 + packages/insomnia-components/index.js | 4 +- .../insomnia-components/package-lock.json | 222 ++ packages/insomnia-components/package.json | 1 + 37 files changed, 4562 insertions(+), 411 deletions(-) delete mode 100644 packages/insomnia-app/app/ui/css/components/spec-editor-sidebar.less create mode 100755 packages/insomnia-cli/dist/cli.js create mode 100644 packages/insomnia-cli/dist/commands/generate.js create mode 100644 packages/insomnia-cli/dist/db/__fixtures__/git-repo-without-insomnia/blank.js create mode 100644 packages/insomnia-cli/dist/db/mem-db.js create mode 100644 packages/insomnia-cli/dist/db/types.js create mode 100644 packages/insomnia-cli/dist/util.js create mode 100644 packages/insomnia-components/assets/icn-brackets.svg create mode 100644 packages/insomnia-components/assets/icn-key.svg delete mode 100644 packages/insomnia-components/components/sidebar.js delete mode 100644 packages/insomnia-components/components/sidebar.stories.js create mode 100644 packages/insomnia-components/components/sidebar/index.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-filter.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-header.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-headers.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-info.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-item.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-panel.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-parameters.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-paths.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-requests.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-responses.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-schemas.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-section.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-security.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-servers.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar-text-item.js create mode 100644 packages/insomnia-components/components/sidebar/sidebar.stories.js create mode 100644 packages/insomnia-components/flow-typed/react-use.js diff --git a/packages/insomnia-app/app/ui/components/spec-editor/spec-editor-sidebar.js b/packages/insomnia-app/app/ui/components/spec-editor/spec-editor-sidebar.js index 76c3f7d1e..a66f024d7 100644 --- a/packages/insomnia-app/app/ui/components/spec-editor/spec-editor-sidebar.js +++ b/packages/insomnia-app/app/ui/components/spec-editor/spec-editor-sidebar.js @@ -2,9 +2,10 @@ import * as React from 'react'; import autobind from 'autobind-decorator'; import YAML from 'yaml'; +import SpecEditorSidebarItem from './spec-editor-sidebar-item'; +import { Sidebar } from 'insomnia-components'; import type { ApiSpec } from '../../../models/api-spec'; import { trackEvent } from '../../../common/analytics'; -import SpecEditorSidebarItem from './spec-editor-sidebar-item'; type Props = {| apiSpec: ApiSpec, @@ -39,6 +40,7 @@ class SpecEditorSidebar extends React.PureComponent { componentDidUpdate() { const { apiSpec } = this.props; const { error } = this.state; + if (apiSpec.type === 'json') { this.setState({ error: @@ -118,6 +120,7 @@ class SpecEditorSidebar extends React.PureComponent { render() { const { error } = this.state; + if (error) { return

{error}

; } @@ -125,6 +128,12 @@ class SpecEditorSidebar extends React.PureComponent { const { apiSpec } = this.props; const specCst = YAML.parseCST(apiSpec.contents); + let specJSON = {}; + + if (apiSpec.contentType === 'yaml') { + specJSON = YAML.parse(apiSpec.contents); + } + if (!specCst) { return null; } @@ -135,9 +144,14 @@ class SpecEditorSidebar extends React.PureComponent { return null; } - const navigationEl = document.contents.map(v => this.renderNext(v, '$')); + // const navigationEl = document.contents.map(v => this.renderNext(v, '$')); - return
{navigationEl}
; + return ( +
+ + {/* navigationEl */} +
+ ); } } diff --git a/packages/insomnia-app/app/ui/css/components/spec-editor-sidebar.less b/packages/insomnia-app/app/ui/css/components/spec-editor-sidebar.less deleted file mode 100644 index 11044863d..000000000 --- a/packages/insomnia-app/app/ui/css/components/spec-editor-sidebar.less +++ /dev/null @@ -1,37 +0,0 @@ -.spec-editor-sidebar { - padding: var(--padding-sm); - overflow: auto; - - li ul { - border-left: 1px dotted var(--hl-lg); - } - - li { - display: block; - width: 100%; - white-space: nowrap; - } - - li > button { - display: inline-block; - height: var(--line-height-xxxs); - - // Extra padding for the textual button so we have - // a larger click area. - &:last-of-type { - padding-right: var(--padding-md); - } - - i { - width: calc(var(--padding-md) * 1.3); - color: var(--hl); - font-size: var(--font-size-lg); - padding: var(--padding-xs); - } - } - - ul ul { - margin-left: var(--padding-md); - padding-left: var(--padding-sm); - } -} diff --git a/packages/insomnia-app/app/ui/css/index.less b/packages/insomnia-app/app/ui/css/index.less index 0604d9afb..cfb0da951 100644 --- a/packages/insomnia-app/app/ui/css/index.less +++ b/packages/insomnia-app/app/ui/css/index.less @@ -53,7 +53,6 @@ @import 'components/sidebar'; @import 'components/spec-editor'; @import 'components/unit-tests'; -@import 'components/spec-editor-sidebar'; @import 'components/tabs'; @import 'components/tag'; @import 'components/themes'; diff --git a/packages/insomnia-app/package-lock.json b/packages/insomnia-app/package-lock.json index 8af527ff2..d6602a40a 100644 --- a/packages/insomnia-app/package-lock.json +++ b/packages/insomnia-app/package-lock.json @@ -1212,7 +1212,6 @@ "version": "0.8.8", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dev": true, "requires": { "@emotion/memoize": "0.7.4" } @@ -1220,8 +1219,7 @@ "@emotion/memoize": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "dev": true + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, "@emotion/serialize": { "version": "0.11.16", @@ -1474,6 +1472,23 @@ "@types/node": ">= 8" } }, + "@popmotion/easing": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@popmotion/easing/-/easing-1.0.2.tgz", + "integrity": "sha512-IkdW0TNmRnWTeWI7aGQIVDbKXPWHVEYdGgd5ZR4SH/Ty/61p63jCjrPxX1XrR7IGkl08bjhJROStD7j+RKgoIw==" + }, + "@popmotion/popcorn": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@popmotion/popcorn/-/popcorn-0.4.4.tgz", + "integrity": "sha512-jYO/8319fKoNLMlY4ZJPiPu8Ea8occYwRZhxpaNn/kZsK4QG2E7XFlXZMJBsTWDw7I1i0uaqyC4zn1nwEezLzg==", + "requires": { + "@popmotion/easing": "^1.0.1", + "framesync": "^4.0.1", + "hey-listen": "^1.0.8", + "style-value-types": "^3.1.7", + "tslib": "^1.10.0" + } + }, "@reach/router": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.3.tgz", @@ -9304,6 +9319,31 @@ "map-cache": "^0.2.2" } }, + "framer-motion": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-1.11.1.tgz", + "integrity": "sha512-CP6aYLPSivAWkq9UoSurefHBggxG85IT8ObYyWYkcZppgtjHzpwRzhaA8P0ljMGRqtcpeQAIybiGgPioBPlOSw==", + "requires": { + "@emotion/is-prop-valid": "^0.8.2", + "@popmotion/easing": "^1.0.2", + "@popmotion/popcorn": "^0.4.2", + "framesync": "^4.0.4", + "hey-listen": "^1.0.8", + "popmotion": "9.0.0-beta-8", + "style-value-types": "^3.1.6", + "stylefire": "^7.0.2", + "tslib": "^1.10.0" + } + }, + "framesync": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-4.0.4.tgz", + "integrity": "sha512-mdP0WvVHe0/qA62KG2LFUAOiWLng5GLpscRlwzBxu2VXOp6B8hNs5C5XlFigsMgrfDrr2YbqTsgdWZTc4RXRMQ==", + "requires": { + "hey-listen": "^1.0.8", + "tslib": "^1.10.0" + } + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -10246,6 +10286,11 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hey-listen": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + }, "highlight.js": { "version": "9.18.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", @@ -14474,6 +14519,19 @@ "@babel/runtime": "^7.8.7" } }, + "popmotion": { + "version": "9.0.0-beta-8", + "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-9.0.0-beta-8.tgz", + "integrity": "sha512-6eQzqursPvnP7ePvdfPeY4wFHmS3OLzNP8rJRvmfFfEIfpFqrQgLsM50Gd9AOvGKJtYJOFknNG+dsnzCpgIdAA==", + "requires": { + "@popmotion/easing": "^1.0.1", + "@popmotion/popcorn": "^0.4.2", + "framesync": "^4.0.4", + "hey-listen": "^1.0.8", + "style-value-types": "^3.1.6", + "tslib": "^1.10.0" + } + }, "popper.js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", @@ -18025,6 +18083,27 @@ } } }, + "style-value-types": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-3.1.7.tgz", + "integrity": "sha512-jPaG5HcAPs3vetSwOJozrBXxuHo9tjZVnbRyBjxqb00c2saIoeuBJc1/2MtvB8eRZy41u/BBDH0CpfzWixftKg==", + "requires": { + "hey-listen": "^1.0.8", + "tslib": "^1.10.0" + } + }, + "stylefire": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/stylefire/-/stylefire-7.0.3.tgz", + "integrity": "sha512-Q0l7NSeFz/OkX+o6/7Zg3VZxSAZeQzQpYomWmIpOehFM/rJNMSLVX5fgg6Q48ut2ETNKwdhm97mPNU643EBCoQ==", + "requires": { + "@popmotion/popcorn": "^0.4.4", + "framesync": "^4.0.0", + "hey-listen": "^1.0.8", + "style-value-types": "^3.1.7", + "tslib": "^1.10.0" + } + }, "sumchecker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz", diff --git a/packages/insomnia-app/package.json b/packages/insomnia-app/package.json index 44fb09df5..56f72bd7b 100644 --- a/packages/insomnia-app/package.json +++ b/packages/insomnia-app/package.json @@ -104,6 +104,7 @@ "electron-context-menu": "^0.10.0", "electron-updater": "^4.2.0", "font-manager": "^0.3.1", + "framer-motion": "^1.11.1", "fs-extra": "^5.0.0", "fuzzysort": "^1.1.1", "graphql": "^14.5.8", diff --git a/packages/insomnia-cli/dist/cli.js b/packages/insomnia-cli/dist/cli.js new file mode 100755 index 000000000..6a9fa8921 --- /dev/null +++ b/packages/insomnia-cli/dist/cli.js @@ -0,0 +1,28 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.go = go; + +var _generate = require("./commands/generate"); + +var _util = require("./util"); + +function makeGenerateCommand(exitOverride) { + // inso generate + const generate = (0, _util.createCommand)(exitOverride, 'generate').description('Code generation utilities'); + const conversionTypes = Object.keys(_generate.ConversionTypeMap).join(', '); // inso generate config -t kubernetes config.yaml + + generate.command('config ').description('Generate configuration from an api spec').requiredOption('-t, --type ', `the type of configuration to generate, options are [${conversionTypes}]`).option('-o, --output ', 'the output path').action((identifier, cmd) => (0, _generate.generateConfig)(identifier, (0, _util.getAllOptions)(cmd))); + return generate; +} + +function go(args, exitOverride) { + if (!args) { + args = process.argv; + } // inso -v + + + (0, _util.createCommand)(!!exitOverride).version((0, _util.getVersion)(), '-v, --version').description('A CLI for Insomnia!').option('--workingDir ', 'Working directory').addCommand(makeGenerateCommand(!!exitOverride)).parseAsync(args).catch(err => console.log('An error occurred', err)); +} \ No newline at end of file diff --git a/packages/insomnia-cli/dist/commands/generate.js b/packages/insomnia-cli/dist/commands/generate.js new file mode 100644 index 000000000..1839f3ba4 --- /dev/null +++ b/packages/insomnia-cli/dist/commands/generate.js @@ -0,0 +1,82 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.generateConfig = generateConfig; +exports.ConversionTypeMap = void 0; + +var o2k = _interopRequireWildcard(require("openapi-2-kong")); + +var _yaml = _interopRequireDefault(require("yaml")); + +var _path = _interopRequireDefault(require("path")); + +var _fs = _interopRequireDefault(require("fs")); + +var _memDb = require("../db/mem-db"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +const ConversionTypeMap = { + kubernetes: 'kong-for-kubernetes', + declarative: 'kong-declarative-config' +}; +exports.ConversionTypeMap = ConversionTypeMap; + +function validateOptions({ + type +}) { + if (!ConversionTypeMap[type]) { + const conversionTypes = Object.keys(ConversionTypeMap).join(', '); + console.log(`Config type "${type}" not unrecognized. Options are [${conversionTypes}].`); + return false; + } + + return true; +} + +async function generateConfig(identifier, options) { + if (!validateOptions(options)) { + return; + } + + const { + type, + output, + workingDir + } = options; + const db = await (0, _memDb.gitDataDirDb)({ + dir: workingDir, + filterTypes: ['ApiSpec'] + }); + let result; + const specFromDb = db.ApiSpec.get(identifier); + + try { + if (specFromDb === null || specFromDb === void 0 ? void 0 : specFromDb.contents) { + result = await o2k.generateFromString(specFromDb.contents, ConversionTypeMap[type]); + } else { + result = await o2k.generate(identifier, ConversionTypeMap[type]); + } + } catch (err) { + console.log('Config failed to generate', err); + return; + } + + const yamlDocs = result.documents.map(d => _yaml.default.stringify(d)); // Join the YAML docs with "---" and strip any extra newlines surrounding them + + const document = yamlDocs.join('\n---\n').replace(/\n+---\n+/g, '\n---\n'); + + if (output) { + const fullOutputPath = _path.default.resolve(output); + + _fs.default.writeFileSync(fullOutputPath, document); + } else { + console.log(document); + } +} \ No newline at end of file diff --git a/packages/insomnia-cli/dist/db/__fixtures__/git-repo-without-insomnia/blank.js b/packages/insomnia-cli/dist/db/__fixtures__/git-repo-without-insomnia/blank.js new file mode 100644 index 000000000..9a390c31f --- /dev/null +++ b/packages/insomnia-cli/dist/db/__fixtures__/git-repo-without-insomnia/blank.js @@ -0,0 +1 @@ +"use strict"; \ No newline at end of file diff --git a/packages/insomnia-cli/dist/db/mem-db.js b/packages/insomnia-cli/dist/db/mem-db.js new file mode 100644 index 000000000..1561a9844 --- /dev/null +++ b/packages/insomnia-cli/dist/db/mem-db.js @@ -0,0 +1,65 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.gitDataDirDb = exports.emptyDb = void 0; + +var _fs = _interopRequireDefault(require("fs")); + +var _path = _interopRequireDefault(require("path")); + +var _yaml = _interopRequireDefault(require("yaml")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const emptyDb = () => ({ + ApiSpec: new Map(), + Environment: new Map(), + Request: new Map(), + RequestGroup: new Map(), + Workspace: new Map() +}); + +exports.emptyDb = emptyDb; + +const gitDataDirDb = async ({ + dir, + filterTypes +}) => { + const db = emptyDb(); + + const insomniaDir = _path.default.normalize(_path.default.join(dir || '.', '.insomnia')); + + if (!_fs.default.existsSync(insomniaDir)) { + // TODO: control logging with verbose flag + // console.log(`Directory not found: ${insomniaDir}`); + return db; + } + + const readAndInsertDoc = async (type, fileName) => { + // Get contents of each file in type dir and insert into data + const contents = await _fs.default.promises.readFile(fileName); + + const obj = _yaml.default.parse(contents.toString()); + + db[type].set(obj._id, obj); + }; + + const types = (filterTypes === null || filterTypes === void 0 ? void 0 : filterTypes.length) ? filterTypes : Object.keys(db); + await Promise.all(types.map(async type => { + // Get all files in type dir + const typeDir = _path.default.join(insomniaDir, type); + + if (!_fs.default.existsSync(typeDir)) { + return; + } + + const files = await _fs.default.promises.readdir(typeDir); + return Promise.all( // Insert each file from each type + files.map(file => readAndInsertDoc(type, _path.default.join(insomniaDir, type, file)))); + })); + return db; +}; + +exports.gitDataDirDb = gitDataDirDb; \ No newline at end of file diff --git a/packages/insomnia-cli/dist/db/types.js b/packages/insomnia-cli/dist/db/types.js new file mode 100644 index 000000000..0aa43ee89 --- /dev/null +++ b/packages/insomnia-cli/dist/db/types.js @@ -0,0 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SpecName = void 0; +// These types should come from a shared location (maybe insomnia-importers?) +// They represent the models that are read from an Insomnia data source +// eg. git data directory, insomnia export format, etc +const SpecName = 'ApiSpec'; +exports.SpecName = SpecName; \ No newline at end of file diff --git a/packages/insomnia-cli/dist/util.js b/packages/insomnia-cli/dist/util.js new file mode 100644 index 000000000..9df916a0e --- /dev/null +++ b/packages/insomnia-cli/dist/util.js @@ -0,0 +1,47 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createCommand = createCommand; +exports.getVersion = getVersion; +exports.getAllOptions = getAllOptions; + +var _commander = _interopRequireDefault(require("commander")); + +var packageJson = _interopRequireWildcard(require("../package.json")); + +function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function createCommand(exitOverride, cmd) { + const command = new _commander.default.Command(cmd).storeOptionsAsProperties(false); + + if (exitOverride) { + return command.exitOverride(); + } + + return command; +} + +function getVersion() { + return packageJson.version; +} + +function getAllOptions(cmd) { + let opts = {}; + let command = cmd; + + do { + // overwrite options with more specific ones + opts = { ...command.opts(), + ...opts + }; + command = command.parent; + } while (command); + + return opts; +} \ No newline at end of file diff --git a/packages/insomnia-components/assets/icn-brackets.svg b/packages/insomnia-components/assets/icn-brackets.svg new file mode 100644 index 000000000..e81e0c9e3 --- /dev/null +++ b/packages/insomnia-components/assets/icn-brackets.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/insomnia-components/assets/icn-key.svg b/packages/insomnia-components/assets/icn-key.svg new file mode 100644 index 000000000..ab8e69974 --- /dev/null +++ b/packages/insomnia-components/assets/icn-key.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/insomnia-components/components/sidebar.js b/packages/insomnia-components/components/sidebar.js deleted file mode 100644 index bbd682ae5..000000000 --- a/packages/insomnia-components/components/sidebar.js +++ /dev/null @@ -1,345 +0,0 @@ -// @flow -import * as React from 'react'; -import { useState } from 'react'; -import { motion } from 'framer-motion'; -import styled from 'styled-components'; -import Tooltip from './tooltip'; -import SvgIcon, { IconEnum } from './svg-icon'; - -type Props = {| - className?: string, -|}; - -const StyledSidebar: React.ComponentType<{}> = styled.div` - /* To constants */ - background-color: var(--color-bg); - border: 1px solid var(--hl-md); - color: var(--color-font); - position: relative; - svg { - font-size: var(--font-size-xl); - fill: var(--hl-lg); - } - .method { - h6 { - font-size: var(--font-size-xxs); - } - } - .method-post { - color: var(--color-success); - } - .method-get { - color: var(--color-surprise); - } - .method-del { - color: var(--color-danger); - } - .method-options-head, - .method-custom { - color: var(--color-info); - } - .method-patch { - color: var(--color-notice); - } - .method-put { - color: var(--color-warning); - } - - h6 { - font-size: var(--font-size-xs); - display: flex; - flex-grow: 1; - &:hover { - cursor: default; - } - } - h5 { - font-size: var(--font-size-sm); - } - /* END To constants */ - width: 260px; - height: 100%; -`; - -const StyledSection: React.ComponentType<{}> = styled(motion.ul)` - overflow: hidden; - box-sizing: border-box; - border-bottom: 1px solid var(--hl-md); -`; - -const StyledHeader: React.ComponentType<{}> = styled.li` - display: flex; - justify-content: space-between; - align-items: center; - - &:hover { - background-color: var(--hl-xs); - } - - & > * { - padding: var(--padding-md) var(--padding-md) var(--padding-md) var(--padding-md); - font-size: var(--font-size-md); - - svg { - margin-left: var(--padding-sm); - - &:hover { - fill: var(--color-font); - opacity: 1; - } - } - } -`; - -const StyledItem: React.ComponentType<{}> = styled.li` - padding: var(--padding-sm) 0 var(--padding-sm) 0; - margin: 0px; - display: grid; - grid-template-columns: repeat(auto-fill, minmax(var(--padding-lg), 1fr)); - column-gap: var(--padding-sm); - grid-template-rows: 1fr; - align-items: start; - white-space: nowrap; - font-size: var(--font-size-md); - line-height: calc(var(--font-size) * 1.25); - - a { - color: var(--hl-xl); - } - - div:nth-child(1) { - text-align: right; - } - - &:hover { - background-color: var(--hl-xxs); - cursor: default; - } - - &:last-child { - margin-bottom: var(--padding-md); - } -`; - -const StyledFilter: React.ComponentType<{}> = styled(motion.div)` - padding-left: var(--padding-md); - padding-right: var(--padding-md); - overflow: hidden; - input { - box-sizing: border-box; - width: 100%; - font-size: var(--font-size-md); - padding: var(--padding-sm); - margin-top: var(--padding-md); - margin-bottom: var(--padding-sm); - } -`; - -const StyledPanel: React.ComponentType<{}> = styled(motion.div)` - height: 0px; -`; - -function Sidebar(props: Props) { - // Temp garbage for easing/transition/sequencing dial-in - const [visible, setVisible] = useState(false); - const [visible2, setVisible2] = useState(false); - const [visible3, setVisible3] = useState(true); - const [visible4, setVisible4] = useState(true); - const toggleVisible = () => setVisible(!visible); - const toggleVisible2 = () => setVisible2(!visible2); - const toggleVisible3 = () => setVisible3(!visible3); - const toggleVisible4 = () => setVisible4(!visible4); - - return ( - - - -
INFO
-
-
- - - -
SERVERS
-
- - - - - - - - - - - -
-
- - - - - - -
- -
-
development.konghq.com
-
- -
- -
-
staging.konghq.com
-
- -
- -
-
production.konghq.com
-
-
-
- - - -
PATHS
-
- - - - - - - - - - - -
-
- - - - - -
- -
-
pet
-
- -
-
POST
-

/store/inventory/(orderId)

-
- -
-
GET
-

/store/inventory/(orderId)

-
- -
-
PUT
-

/store/inventory/(orderId)

-
- -
-
DEL
-

/store/inventory/(orderId)

-
- -
-
POST
-

/store/inventory/(orderId)

-
- -
-
PUT
-

/store/inventory/(orderId)

-
- -
- -
-
store
-
- -
-
PUT
-

/store/inventory/(orderId)

-
- -
-
DEL
-

/store/inventory/(orderId)

-
- -
-
POST
-

/store/inventory/(orderId)

-
- -
-
PUT
-

/store/inventory/(orderId)

-
- -
- -
-
user
-
-
-
- - - -
MODELS
- -
-
- - - -
SECURITY
- -
-
-
- ); -} - -export default Sidebar; diff --git a/packages/insomnia-components/components/sidebar.stories.js b/packages/insomnia-components/components/sidebar.stories.js deleted file mode 100644 index 00ff4e1e6..000000000 --- a/packages/insomnia-components/components/sidebar.stories.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import Sidebar from './sidebar'; -import { withKnobs } from '@storybook/addon-knobs'; -import { withDesign } from 'storybook-addon-designs'; - -export default { - title: '1st Party | Sidebar', - decorators: [withKnobs, withDesign], -}; - -export const _default = () => ; - -_default.story = { - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/sS7oBbKmDvhtq5lXyTckVe/Style-Guide-Components?node-id=0%3A2', - }, - }, -}; diff --git a/packages/insomnia-components/components/sidebar/index.js b/packages/insomnia-components/components/sidebar/index.js new file mode 100644 index 000000000..f0949dbdb --- /dev/null +++ b/packages/insomnia-components/components/sidebar/index.js @@ -0,0 +1,165 @@ +// @flow +import * as React from 'react'; +import { motion } from 'framer-motion'; +import styled from 'styled-components'; +import SidebarHeader from './sidebar-header'; +import SidebarInfo from './sidebar-info'; +import SidebarServers from './sidebar-servers'; +import SidebarPaths from './sidebar-paths'; +import SidebarRequests from './sidebar-requests'; +import SidebarResponses from './sidebar-responses'; +import SidebarParameters from './sidebar-parameters'; +import SidebarHeaders from './sidebar-headers'; +import SidebarSchemas from './sidebar-schemas'; +import SidebarSecurity from './sidebar-security'; +import Dropdown from '../dropdown/dropdown'; +import DropdownItem from '../dropdown/dropdown-item'; +import DropdownDivider from '../dropdown/dropdown-divider'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import { useToggle } from 'react-use'; + +type Props = {| + className?: string, + jsonData: Object, +|}; + +const StyledSidebar: React.ComponentType<{}> = styled.div` + width: 100%; + height: 100%; + background-color: var(--color-bg); + border: none; + color: var(--color-font); + position: relative; + svg { + font-size: var(--font-size-xl); + fill: var(--hl-lg); + } + ul:first-child { + border-top: none; + } + ul:last-child { + border-bottom: none; + } +`; + +const StyledSection: React.ComponentType<{}> = styled(motion.ul)` + overflow: hidden; + box-sizing: border-box; + border-bottom: 1px solid var(--hl-md); +`; + +const DropdownEllipsis = () => ; +// Section Expansion & Filtering + +function Sidebar(props: Props) { + // Section Visibility + const [infoSec, setInfoSec] = useToggle(false); + const [pathsVisible, setPathsVisible] = useToggle(true); + const [serversVisible, setServersVisible] = useToggle(true); + const [requestsVisible, setRequestsVisible] = useToggle(true); + const [responsesVisible, setResponsesVisible] = useToggle(true); + const [parametersVisible, setParametersVisible] = useToggle(true); + const [headersVisible, setHeadersVisible] = useToggle(true); + const [schemasVisible, setSchemasVisible] = useToggle(true); + const [securityVisible, setSecurityVisible] = useToggle(true); + + // Sections + if (props.jsonData === null) { + return null; + } + const { servers, info } = props.jsonData; + const { + requestBodies, + responses, + parameters, + headers, + schemas, + securitySchemes, + } = props.jsonData.components; + const paths = Object.entries(props.jsonData.paths); + + return ( + + {info && ( + + + + VISIBILITY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + {serversVisible && servers && } + {pathsVisible && paths && } + {requestsVisible && requestBodies && } + {responsesVisible && responses && } + {parametersVisible && parameters && } + {headersVisible && headers && } + {schemasVisible && schemas && } + {securityVisible && schemas && } + + ); +} + +export default Sidebar; diff --git a/packages/insomnia-components/components/sidebar/sidebar-filter.js b/packages/insomnia-components/components/sidebar/sidebar-filter.js new file mode 100644 index 000000000..bd1dab33a --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-filter.js @@ -0,0 +1,57 @@ +// @flow +import * as React from 'react'; +import { useLayoutEffect } from 'react'; +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +type Props = { + filter: boolean, + onChange?: (e: SyntheticInputEvent) => any, +}; + +const StyledFilter: React.ComponentType<{}> = styled(motion.div)` + padding-left: var(--padding-md); + padding-right: var(--padding-md); + overflow: hidden; + input { + box-sizing: border-box; + width: 100%; + font-size: var(--font-size-sm); + padding: var(--padding-xs); + margin-top: 0; + margin-bottom: var(--padding-sm); + outline-style: none; + box-shadow: none; + border: 1px solid var(--hl-md); + color: var(--color-font); + background: transparent; + + :focus::placeholder { + color: transparent; + } + + ::placeholder { + color: var(--color-font); + } + } +`; + +const SidebarFilter = ({ filter, onChange }: Props) => { + const filterField = React.createRef(); + + useLayoutEffect(() => { + if (filterField.current && !filter) { + filterField.current.value = ''; + } + }, [filter, filterField]); + + return ( + + + + ); +}; + +export default SidebarFilter; diff --git a/packages/insomnia-components/components/sidebar/sidebar-header.js b/packages/insomnia-components/components/sidebar/sidebar-header.js new file mode 100644 index 000000000..e4f022180 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-header.js @@ -0,0 +1,80 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; +import { motion } from 'framer-motion'; +import SvgIcon, { IconEnum } from '../svg-icon'; + +type Props = { + headerTitle: string, + toggleSection: (toggle: SyntheticKeyboardEvent) => void, + toggleFilter?: () => void, + sectionVisible: boolean, + children?: React.Node, +}; + +const StyledHeader: React.ComponentType<{}> = styled.li` + display: flex; + justify-content: space-between; + align-items: center; + + &:hover { + background-color: var(--hl-xs); + } + + h6 { + font-size: var(--font-size-xs); + display: flex; + flex-grow: 1; + &:hover { + cursor: default; + } + } + + h6:hover { + text-decoration: underline; + } + + label { + color: red !important; + position: absolute; + padding-top: var(--padding-xs); + } + + & > * { + padding: var(--padding-md) var(--padding-md) var(--padding-md) var(--padding-md); + font-size: var(--font-size-md); + + svg { + margin-left: var(--padding-sm); + + &:hover { + fill: var(--color-font); + opacity: 1; + } + } + } +`; + +const SidebarHeader = ({ + headerTitle, + toggleSection, + toggleFilter, + sectionVisible, + children, +}: Props) => ( + +
{headerTitle}
+
+ {children || ( + + + + )} +
+
+); + +export default SidebarHeader; diff --git a/packages/insomnia-components/components/sidebar/sidebar-headers.js b/packages/insomnia-components/components/sidebar/sidebar-headers.js new file mode 100644 index 000000000..c983046f9 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-headers.js @@ -0,0 +1,53 @@ +// @flow +import * as React from 'react'; +import Tooltip from '../tooltip'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + headers: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('header'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarHeaders extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.headers).filter(header => + header.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(header => ( + + +
+ +
+ handleClick([header])}> + + {header} + + +
+
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-info.js b/packages/insomnia-components/components/sidebar/sidebar-info.js new file mode 100644 index 000000000..3a4a3a8e8 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-info.js @@ -0,0 +1,40 @@ +// @flow +import * as React from 'react'; +import SidebarPanel from './sidebar-panel'; +import SidebarItem from './sidebar-item'; +import SidebarTextItem from './sidebar-text-item'; + +type Props = { + info: Object, + childrenVisible: boolean, +}; + +function SidebarInfo(props: Props) { + const { title, description, version, license } = props.info; + return ( + + {title && ( + + + + )} + {description && ( + + + + )} + {version && ( + + + + )} + {license.name && ( + + + + )} + + ); +} + +export default SidebarInfo; diff --git a/packages/insomnia-components/components/sidebar/sidebar-item.js b/packages/insomnia-components/components/sidebar/sidebar-item.js new file mode 100644 index 000000000..7967fec3b --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-item.js @@ -0,0 +1,84 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; + +type Props = { + children: React.Node, + gridLayout?: boolean, +}; + +const StyledBlockItem: React.ComponentType<{}> = styled.div` + padding: 0 var(--padding-md) var(--padding-sm) 0; + margin: 0; + display: block; + font-size: var(--font-size-md); + line-height: var(--font-size-sm); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + &:hover { + background-color: var(--hl-xxs); + cursor: default; + } + &:last-child { + margin-bottom: var(--padding-md); + } + span { + margin: 0 0 0 var(--padding-sm); + } + div { + display: inline; + margin: 0; + } + div:nth-child(1) { + padding-left: var(--padding-sm); + } + div.tooltip { + padding: 0; + } +`; + +const StyledGridItem: React.ComponentType<{}> = styled.li` + padding: 0 0 0 var(--padding-sm); + margin: 0; + display: grid; + grid-template-columns: 0.25fr 5fr; + column-gap: var(--padding-sm); + grid-template-rows: 1fr; + align-items: start; + white-space: nowrap; + font-size: var(--font-size-md); + line-height: var(--font-size-sm); + span { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + padding: 4px var(--padding-sm) var(--padding-xs) 0px; + } + a { + color: var(--hl-xl); + } + div:nth-child(1) { + text-align: right; + svg { + padding-left: var(--padding-sm); + } + } + &:hover { + background-color: var(--hl-xxs); + cursor: default; + } + &:last-child { + margin-bottom: var(--padding-md); + } +`; + +const SidebarItem = ({ children, gridLayout }: Props) => { + if (gridLayout) { + return {children}; + } else { + return {children}; + } +}; + +export default SidebarItem; diff --git a/packages/insomnia-components/components/sidebar/sidebar-panel.js b/packages/insomnia-components/components/sidebar/sidebar-panel.js new file mode 100644 index 000000000..688a0218c --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-panel.js @@ -0,0 +1,51 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; +import { motion } from 'framer-motion'; + +type Props = { + children: React.Node, + childrenVisible: boolean, +}; + +const StyledPanel: React.ComponentType<{}> = styled(motion.div)` + height: 0; + .method { + h6 { + font-size: var(--font-size-xxs); + } + } + .method-post { + color: var(--color-success); + } + .method-get { + color: var(--color-surprise); + } + .method-delete { + color: var(--color-danger); + } + .method-parameters { + display: none; + } + .method-options-head, + .method-custom { + color: var(--color-info); + } + .method-patch { + color: var(--color-notice); + } + .method-put { + color: var(--color-warning); + } +`; + +const SidebarPanel = ({ childrenVisible, children }: Props) => ( + + {children} + +); + +export default SidebarPanel; diff --git a/packages/insomnia-components/components/sidebar/sidebar-parameters.js b/packages/insomnia-components/components/sidebar/sidebar-parameters.js new file mode 100644 index 000000000..ab2029152 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-parameters.js @@ -0,0 +1,54 @@ +// @flow +import * as React from 'react'; +import Tooltip from '../tooltip'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + parameters: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('parameter'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarParameters extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.parameters).filter(parameter => + parameter.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(parameter => ( + + +
+ +
+ handleClick([parameter])}> + + {parameter} + + +
+
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-paths.js b/packages/insomnia-components/components/sidebar/sidebar-paths.js new file mode 100644 index 000000000..f36803693 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-paths.js @@ -0,0 +1,66 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + paths: Array, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('path'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +const StyledMethods: React.ComponentType<{}> = styled.span` + padding-left: var(--padding-lg); +`; + +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarPaths extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = this.props.paths.filter(pathDetail => + pathDetail[0].toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(([route, method]) => ( + + +
+ +
+ handleClick([route])}>{route} +
+ + + {Object.keys((method: any)).map(method => ( + handleClick([route, method])}> + {method} + + ))} + + +
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-requests.js b/packages/insomnia-components/components/sidebar/sidebar-requests.js new file mode 100644 index 000000000..836c5057a --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-requests.js @@ -0,0 +1,88 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; +import Tooltip from '../tooltip'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + requests: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('request'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +const StyledRequestExample: React.ComponentType<{}> = styled.span` + color: var(--color-success); + &:first-of-type { + padding-left: var(--padding-lg); + } +`; + +const StyledRequestFormat: React.ComponentType<{}> = styled.span` + padding-left: var(--padding-sm); +`; + +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarRequests extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.requests).filter(requestName => + requestName.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(requestName => { + const { description, content } = this.props.requests[requestName]; + return ( + + +
+ +
+ handleClick([requestName])}> + + {requestName} + + +
+ {Object.keys(content).map(requestFormat => ( + + + + + handleClick([requestFormat])}>{requestFormat} + + + + {Object.keys(content[requestFormat].examples).map(requestExample => ( + handleClick([requestExample])} + key={requestExample}> + {requestExample} + + ))} + + + ))} +
+ ); + })} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-responses.js b/packages/insomnia-components/components/sidebar/sidebar-responses.js new file mode 100644 index 000000000..e75e43fc9 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-responses.js @@ -0,0 +1,52 @@ +// @flow +import * as React from 'react'; +import Tooltip from '../tooltip'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + responses: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('response'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarResponses extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.responses).filter(response => + response.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(response => ( + +
+ +
+ handleClick([response])}> + + {response} + + +
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-schemas.js b/packages/insomnia-components/components/sidebar/sidebar-schemas.js new file mode 100644 index 000000000..f6c817507 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-schemas.js @@ -0,0 +1,47 @@ +// @flow +import * as React from 'react'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + schemas: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('schema'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarSchemas extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.schemas).filter(schema => + schema.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(schema => ( + +
+ +
+ handleClick([schema])}>{schema} +
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-section.js b/packages/insomnia-components/components/sidebar/sidebar-section.js new file mode 100644 index 000000000..0440cddc5 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-section.js @@ -0,0 +1,59 @@ +// @flow +import * as React from 'react'; +import { useLayoutEffect } from 'react'; +import SidebarHeader from './sidebar-header'; +import SidebarPanel from './sidebar-panel'; +import SidebarFilter from './sidebar-filter'; +import styled from 'styled-components'; +import { motion } from 'framer-motion'; +import { useToggle } from 'react-use'; + +type SectionProps = { + title: string, + renderBody: (filterValue: string) => React.Node, +}; + +const StyledSection: React.ComponentType<{}> = styled(motion.ul)` + overflow: hidden; + box-sizing: border-box; + border-bottom: 1px solid var(--hl-md); +`; + +const StyledNoResults: React.ComponentType<{}> = styled.div` + padding: var(--padding-xs) var(--padding-xs) var(--padding-md) var(--padding-md); + color: var(--color-warning); +`; + +const SidebarSection = ({ title, renderBody }: SectionProps) => { + const [bodyVisible, toggleBodyVisible] = useToggle(false); + const [filterVisible, toggleFilterVisible] = useToggle(false); + const [filterValue, setFilterValue] = React.useState(''); + + const handleFilterChange = React.useCallback((e: SyntheticInputEvent) => { + setFilterValue(e.target.value); + }, []); + + useLayoutEffect(() => { + toggleFilterVisible(false); + setFilterValue(''); + }, [bodyVisible, toggleFilterVisible]); + + return ( + + + + + {renderBody(filterValue) || ( + No results found for "{filterValue}"... + )} + + + ); +}; + +export default SidebarSection; diff --git a/packages/insomnia-components/components/sidebar/sidebar-security.js b/packages/insomnia-components/components/sidebar/sidebar-security.js new file mode 100644 index 000000000..47525146c --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-security.js @@ -0,0 +1,48 @@ +// @flow +import * as React from 'react'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + security: Object, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('security'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarSecurity extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = Object.keys(this.props.security).filter(scheme => + scheme.toLowerCase().includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(scheme => ( + + +
+ +
+ handleClick([scheme])}>{scheme} +
+
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-servers.js b/packages/insomnia-components/components/sidebar/sidebar-servers.js new file mode 100644 index 000000000..86b0f0594 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-servers.js @@ -0,0 +1,48 @@ +// @flow +import * as React from 'react'; +import SidebarItem from './sidebar-item'; +import SvgIcon, { IconEnum } from '../svg-icon'; +import SidebarSection from './sidebar-section'; + +type Props = { + servers: Array, +}; + +let itemPath = []; +const handleClick = items => { + itemPath.push('server'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; +// Implemented as a class component because of a caveat with render props +// https://reactjs.org/docs/render-props.html#be-careful-when-using-render-props-with-reactpurecomponent +export default class SidebarServers extends React.Component { + renderBody = (filter: string): null | React.Node => { + const filteredValues = this.props.servers.filter(server => + server.url.includes(filter.toLocaleLowerCase()), + ); + + if (!filteredValues.length) { + return null; + } + + return ( +
+ {filteredValues.map(server => ( + + +
+ +
+ handleClick([server.url])}>{server.url} +
+
+ ))} +
+ ); + }; + + render() { + return ; + } +} diff --git a/packages/insomnia-components/components/sidebar/sidebar-text-item.js b/packages/insomnia-components/components/sidebar/sidebar-text-item.js new file mode 100644 index 000000000..32a4bd083 --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar-text-item.js @@ -0,0 +1,32 @@ +// @flow +import * as React from 'react'; +import styled from 'styled-components'; + +type Props = { + label: string, + headline: string, +}; + +const StyledTextItem: React.ComponentType<{}> = styled.span` + display: block; + padding-left: var(--padding-sm); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +`; + +let itemPath = []; +const handleClick = items => { + itemPath.push('info'); + itemPath.push.apply(itemPath, items); + itemPath = []; +}; + +const SidebarTextItem = ({ label, headline }: Props) => ( + + {label} + handleClick([headline])}>{headline} + +); + +export default SidebarTextItem; diff --git a/packages/insomnia-components/components/sidebar/sidebar.stories.js b/packages/insomnia-components/components/sidebar/sidebar.stories.js new file mode 100644 index 000000000..c6a0ddf0d --- /dev/null +++ b/packages/insomnia-components/components/sidebar/sidebar.stories.js @@ -0,0 +1,2960 @@ +import React from 'react'; +import Sidebar from './'; +import { withKnobs } from '@storybook/addon-knobs'; +import { withDesign } from 'storybook-addon-designs'; + +export default { + title: '1st Party | Sidebar', + decorators: [withKnobs, withDesign], +}; +const apiSpec = { + openapi: '3.0.0', + info: { + title: 'A Kong Admin API', + version: '1.3', + contact: { + name: 'Kong', + }, + license: { + name: 'Apache 2.0', + }, + description: 'This is the description for my specification', + }, + servers: [ + { + url: 'https://dev.kongonghq.com/v1', + description: 'Development server', + }, + { + url: 'https://staging.konghq.com/v1', + description: 'Staging server', + }, + { + url: 'https://api.konghq.com/v1', + description: 'Production server', + }, + ], + tags: [ + { + name: 'Tags', + description: '', + }, + ], + paths: { + '/tags': { + get: { + summary: 'List Tags', + tags: ['Tags'], + responses: { + '200': { + description: 'List of Tags in the system', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/TagsResponse', + }, + examples: { + 'Response Body': { + value: { + data: [ + { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's1', + }, + { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's2', + }, + { + entity_name: 'routes', + entity_id: '60631e85-ba6d-4c59-bd28-e36dd90f6000', + tag: 's1', + }, + ], + offset: 'c47139f3-d780-483d-8a97-17e9adc5a7ab', + next: '/tags?offset=c47139f3-d780-483d-8a97-17e9adc5a7ab', + }, + }, + }, + }, + }, + }, + }, + description: 'Returns a paginated list of all the tags in the system.', + operationId: 'list-tags', + parameters: [], + }, + }, + '/tags/{tag}': { + get: { + summary: 'List Tags by Tag Name', + tags: ['Tags'], + responses: { + '200': { + description: 'List of entities tagged with the specified tag', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/TagsResponse', + }, + examples: { + 'Response Body': { + value: { + data: [ + { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's1', + }, + { + entity_name: 'routes', + entity_id: '60631e85-ba6d-4c59-bd28-e36dd90f6000', + tag: 's1', + }, + ], + offset: 'c47139f3-d780-483d-8a97-17e9adc5a7ab', + next: '/tags?offset=c47139f3-d780-483d-8a97-17e9adc5a7ab', + }, + }, + }, + }, + }, + }, + }, + description: 'Returns the entities that have been tagged with the specified tag.', + operationId: 'list-tags-by-name', + parameters: [ + { + schema: { + type: 'string', + pattern: '^[A-Za-z-_\\.~]+', + }, + name: 'tag', + in: 'path', + required: true, + description: 'Tag Value', + }, + ], + }, + }, + '/services': { + get: { + summary: 'List Services', + tags: ['Services'], + responses: { + '200': { + description: 'Paginated list of service entities', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ServicesResponse', + }, + examples: { + 'Response Body': { + value: { + data: [ + { + id: '4e3ad2e4-0bc4-4638-8e34-c84a417ba39b', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + { + id: 'a5fb8d9b-a99d-40e9-9d35-72d42a62d83a', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/another_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: + 'http://localhost:8001/services?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + }, + }, + }, + }, + parameters: [ + { + schema: { + type: 'string', + }, + in: 'query', + name: 'offset', + description: 'Cursor used for pagination', + }, + { + schema: { + type: 'number', + maximum: 1000, + minimum: 1, + default: '100', + exclusiveMaximum: false, + }, + in: 'query', + name: 'size', + description: 'A limit on the number of objects to be returned per page.', + }, + { + schema: { + type: 'string', + }, + in: 'query', + name: 'tags', + description: + 'List of tags to filter by. Comma separated. Or clause denoted by slash (example/admin) example or admin. Maximum of 5 operations per request (, or /).', + }, + ], + description: 'Returns a list of services', + operationId: 'list-services', + }, + post: { + summary: 'Create Service', + responses: { + '201': { + description: 'Service created', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Service', + }, + examples: { + 'Response Body': { + value: { + id: '9748f662-7711-4a90-8186-dc02f10eb0f5', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + }, + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ServiceRequest', + }, + examples: { + 'Request Body': { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + description: 'RB Description', + }, + description: 'Create new service entity', + operationId: 'create-service', + tags: ['Services'], + parameters: [], + }, + }, + '/services/{service_name_or_id}': { + parameters: [ + { + schema: { + type: 'string', + }, + name: 'service_name_or_id', + in: 'path', + required: true, + description: + 'The unique identifier or the name of the Service to view, modify, or delete.', + }, + ], + get: { + summary: 'View Service', + tags: ['Services'], + responses: { + '200': { + description: 'Return specified service details', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Service', + }, + examples: { + 'Response Body': { + value: { + id: '9748f662-7711-4a90-8186-dc02f10eb0f5', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + }, + operationId: 'view-service', + description: 'Returns specified service details', + }, + put: { + summary: 'Create or Update Service', + tags: ['Services'], + responses: { + '200': { + description: 'Service Updated', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Service', + }, + examples: { + 'Response Body': { + value: { + id: '9748f662-7711-4a90-8186-dc02f10eb0f5', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + '201': { + description: 'Service Created', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Service', + }, + examples: { + 'Response Body': { + value: { + id: '9748f662-7711-4a90-8186-dc02f10eb0f5', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + }, + description: 'Create or Update Service', + operationId: 'create-or-update-service', + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/ServiceRequest', + }, + examples: { + 'Request Body': { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + }, + delete: { + summary: 'Delete Service', + tags: ['Services'], + responses: { + '204': { + description: 'No Content', + }, + }, + description: '', + operationId: 'delete-service', + }, + }, + '/services/{service_name_or_id}/routes': { + parameters: [ + { + schema: { + type: 'string', + }, + name: 'service_name_or_id', + in: 'path', + required: true, + description: + 'The unique identifier or the name of the Service to view, modify, or delete.', + }, + ], + get: { + summary: 'List Routes for specified Service Name / Id', + tags: ['Service Routes'], + responses: { + '200': { + description: 'Paginated list of route entities for specified service', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/RoutesResponse', + }, + examples: { + 'Response Body': { + value: { + data: [ + { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + { + id: 'af8330d3-dbdc-48bd-b1be-55b98608834b', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['tcp', 'tls'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + snis: ['foo.test', 'example.com'], + sources: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + destinations: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + tags: ['admin', 'high-priority', 'critical'], + service: { + id: 'a9daa3ba-8186-4a0d-96e8-00d80ce7240b', + }, + }, + ], + next: + 'http://localhost:8001/routes?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + }, + }, + }, + }, + description: 'Returns a paginated list of routes for specified service id', + operationId: 'list-routes-by-service-name-or-id', + parameters: [ + { + schema: { + type: 'string', + }, + in: 'query', + name: 'offset', + description: 'Cursor used for pagination', + }, + { + schema: { + type: 'number', + maximum: 1000, + minimum: 1, + default: '100', + exclusiveMaximum: false, + }, + in: 'query', + name: 'size', + description: 'A limit on the number of objects to be returned per page.', + }, + { + schema: { + type: 'string', + }, + in: 'query', + name: 'tags', + description: + 'List of tags to filter by. Comma separated. Or clause denoted by slash (example/admin) example or admin. Maximum of 5 operations per request (, or /).', + }, + ], + }, + post: { + summary: 'Create Route associated to specific Service', + responses: { + '201': { + description: 'Route created', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Route', + }, + examples: { + 'Response Body': { + value: { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + }, + }, + }, + }, + }, + }, + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/RouteRequest', + }, + examples: { + 'Request Body': { + value: { + name: 'my-route', + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + description: '', + }, + description: 'Create new route entity', + operationId: 'create-route-by-service', + tags: ['Service Routes'], + parameters: [], + }, + }, + '/services/{service_name_or_id}/routes/{route_name_or_id}': { + parameters: [ + { + schema: { + type: 'string', + }, + name: 'service_name_or_id', + in: 'path', + required: true, + description: + 'The unique identifier or the name of the Service associated to the specified route.', + }, + { + schema: { + type: 'string', + }, + name: 'route_name_or_id', + in: 'path', + required: true, + description: 'The unique identifier or the name of the Route to view, modify, or delete.', + }, + ], + get: { + summary: 'View Route associated with specified Service', + tags: ['Service Route'], + responses: { + '200': { + description: 'Return specified route details', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Route', + }, + examples: { + 'Response Body': { + value: { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + }, + }, + }, + }, + }, + }, + operationId: 'view-route-by-service', + description: 'Returns specified route details', + }, + put: { + summary: 'Create or Update Route by Service', + tags: ['Service Route'], + responses: { + '200': { + description: 'Route Updated', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Route', + }, + examples: { + 'Response Body': { + value: { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + }, + }, + }, + }, + }, + '201': { + description: 'Route Created', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Route', + }, + examples: { + 'Response Body': { + value: { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + }, + }, + }, + }, + }, + }, + description: 'Create or Update Route by Service', + operationId: 'create-or-update-route-by-service', + requestBody: { + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/RouteRequest', + }, + examples: { + 'Request Body': { + value: { + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + }, + }, + }, + }, + }, + }, + delete: { + summary: 'Delete Route associated to specified Service', + tags: ['Service Route'], + responses: { + '204': { + description: 'No Content', + }, + }, + description: '', + operationId: 'delete-route-by-service', + }, + }, + }, + components: { + requestBodies: { + PetBody: { + description: 'A JSON object containing pet information', + required: true, + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + 'application/xml': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + 'text/plain': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + StoreBody: { + description: 'A JSON object containing store information', + required: true, + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + 'application/xml': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + 'text/plain': { + schema: { + $ref: '#/components/schemas/Pet', + }, + examples: { + dog: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + cat: { + value: { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + }, + }, + }, + }, + }, + schemas: { + Service: { + title: 'Service Entity', + type: 'object', + 'x-examples': { + Entity: { + id: '9748f662-7711-4a90-8186-dc02f10eb0f5', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + }, + description: + 'Service entities, as the name implies, are abstractions of each of your own upstream services.', + properties: { + id: { + type: 'string', + format: 'uuid', + }, + created_at: { + type: 'number', + }, + updated_at: { + type: 'number', + }, + name: { + type: 'string', + description: 'Service Name (a-z-_)', + example: 'my-service', + pattern: '^[a-z-_]+', + }, + retries: { + type: 'number', + description: 'The number of retries to execute upon failure to proxy.', + }, + protocol: { + type: 'string', + description: 'The protocol used to communicate with the upstream.', + enum: ['http', 'https', 'grpc', 'grpcs', 'tcp', 'tls'], + }, + host: { + type: 'string', + description: 'The host of the upstream server.', + }, + port: { + type: 'number', + description: 'The port of the upstream server.', + }, + path: { + type: 'string', + example: '/some_api', + pattern: '^\\/(.*)+', + description: 'The path to be used in requests to the upstream server.', + }, + connect_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds for establishing a connection to the upstream server.', + }, + write_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds between two successive write operations for transmitting a request to the upstream server.', + }, + read_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds between two successive read operations for transmitting a request to the upstream server.', + }, + client_certificate: { + type: 'object', + description: + 'Certificate to be used as client certificate while TLS handshaking to the upstream server.', + properties: { + id: { + type: 'string', + }, + }, + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + }, + }, + ServiceRequest: { + title: 'Service Request Body', + type: 'object', + 'x-examples': { + 'Request Body': { + name: 'my-service', + url: 'http://example.com/some_api', + tags: ['user-level', 'low-priority'], + }, + }, + description: + 'Service entities, as the name implies, are abstractions of each of your own upstream services.', + properties: { + name: { + type: 'string', + description: 'Service Name (a-z-_)', + example: 'my-service', + pattern: '^[a-z-_]+', + }, + retries: { + type: 'number', + description: 'The number of retries to execute upon failure to proxy.', + }, + connect_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds for establishing a connection to the upstream server.', + }, + write_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds between two successive write operations for transmitting a request to the upstream server.', + }, + read_timeout: { + type: 'number', + example: '60000', + description: + 'The timeout in milliseconds between two successive read operations for transmitting a request to the upstream server.', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + client_certificate: { + type: 'object', + description: + 'Certificate to be used as client certificate while TLS handshaking to the upstream server.', + properties: { + id: { + type: 'string', + }, + }, + }, + url: { + type: 'string', + description: 'Shorthand attribute to set protocol, host, port and path at once.', + example: 'http://example.com/some_api', + }, + }, + required: ['url'], + }, + TagsResponse: { + title: 'Tags Response', + type: 'object', + 'x-examples': { + 'Response Body': { + data: [ + { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's1', + }, + { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's2', + }, + { + entity_name: 'routes', + entity_id: '60631e85-ba6d-4c59-bd28-e36dd90f6000', + tag: 's1', + }, + ], + offset: 'c47139f3-d780-483d-8a97-17e9adc5a7ab', + next: '/tags?offset=c47139f3-d780-483d-8a97-17e9adc5a7ab', + }, + }, + properties: { + data: { + type: 'array', + items: { + $ref: '#/components/schemas/TagEntity', + }, + }, + offset: { + type: 'string', + }, + next: { + type: 'string', + }, + }, + }, + TagEntity: { + title: 'Tag Entity', + type: 'object', + 'x-examples': { + TAG: { + entity_name: 'services', + entity_id: 'acf60b10-125c-4c1a-bffe-6ed55daefba4', + tag: 's1', + }, + }, + description: 'Tag Entity', + properties: { + entity_name: { + type: 'string', + }, + entity_id: { + type: 'string', + }, + tag: { + $ref: '#/components/schemas/Tag', + }, + }, + }, + Route: { + title: 'Route Entity', + type: 'object', + 'x-examples': { + HOSTS: { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + SNIS: { + id: 'af8330d3-dbdc-48bd-b1be-55b98608834b', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['tcp', 'tls'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + snis: ['foo.test', 'example.com'], + sources: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + destinations: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + tags: ['admin', 'high-priority', 'critical'], + service: { + id: 'a9daa3ba-8186-4a0d-96e8-00d80ce7240b', + }, + }, + }, + description: 'Route entities define rules to match client requests.', + properties: { + id: { + type: 'string', + format: 'uuid', + example: '51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515', + }, + service: { + type: 'object', + description: 'The Service this Route is associated to.', + properties: { + id: { + type: 'string', + }, + }, + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + preserve_host: { + type: 'boolean', + example: false, + description: + 'When matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers.', + }, + strip_path: { + type: 'boolean', + default: true, + description: + 'When matching a Route via one of the paths, strip the matching prefix from the upstream request URL. ', + example: true, + }, + regex_priority: { + type: 'integer', + default: 0, + description: + 'A number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used.', + example: 0, + }, + https_redirect_status_code: { + type: 'integer', + default: 426, + description: + 'The status code Kong responds with when all properties of a Route match except the protocol', + example: 426, + }, + paths: { + type: 'array', + description: 'A list of paths that match this Route.', + items: { + type: 'string', + }, + }, + hosts: { + type: 'array', + description: 'A list of domain names that match this Route.', + items: { + type: 'string', + }, + }, + methods: { + type: 'array', + description: 'A list of HTTP methods that match this Route.', + items: { + type: 'string', + }, + }, + protocols: { + type: 'array', + default: ['http', 'https'], + description: 'A list of the protocols this Route should allow.', + enum: ['http', 'https'], + items: { + type: 'string', + }, + }, + name: { + type: 'string', + pattern: '^[a-z-_]+', + example: 'my-route', + description: 'The name of the Route.', + }, + updated_at: { + type: 'integer', + example: 1422386534, + }, + created_at: { + type: 'integer', + example: 1422386534, + }, + snis: { + description: + 'A list of SNIs that match this Route when using stream routing. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + type: 'array', + items: { + type: 'string', + }, + }, + sources: { + description: + 'A list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + type: 'array', + items: { + type: 'string', + }, + }, + destinations: { + type: 'array', + description: + 'A list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + items: { + type: 'string', + }, + }, + }, + }, + Certificate: { + title: 'Certificate Entity', + type: 'object', + 'x-examples': { + Entity: { + id: 'ce44eef5-41ed-47f6-baab-f725cecf98c7', + created_at: 1422386534, + cert: '-----BEGIN CERTIFICATE-----...', + key: '-----BEGIN RSA PRIVATE KEY-----...', + tags: ['user-level', 'low-priority'], + }, + }, + properties: { + id: { + type: 'string', + format: 'uuid', + }, + created_at: { + type: 'number', + }, + cert: { + type: 'string', + description: 'PEM-encoded public certificate of the SSL key pair.', + }, + key: { + type: 'string', + description: 'PEM-encoded private key of the SSL key pair.', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + }, + description: + 'A certificate object represents a public certificate, and can be optionally paired with the corresponding private key. These objects are used by Kong to handle SSL/TLS termination for encrypted requests, or for use as a trusted CA store when validating peer certificate of client/service. Certificates are optionally associated with SNI objects to tie a cert/key pair to one or more hostnames.', + }, + UpstreamTarget: { + title: 'Upstream Target Entity', + type: 'object', + 'x-examples': { + Entity: { + id: 'a3395f66-2af6-4c79-bea2-1b6933764f80', + created_at: 1422386534, + upstream: { + id: '885a0392-ef1b-4de3-aacf-af3f1697ce2c', + }, + target: 'example.com:8000', + weight: 100, + tags: ['user-level', 'low-priority'], + }, + }, + properties: { + id: { + type: 'string', + }, + created_at: { + type: 'number', + }, + upstream: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, + target: { + type: 'string', + description: + 'The target address (ip or hostname) and port. If the hostname resolves to an SRV record, the port value will be overridden by the value from the DNS record.', + }, + weight: { + type: 'integer', + default: 100, + description: + 'The weight this target gets within the upstream loadbalancer (`0`-`1000`). If the hostname resolves to an SRV record, the weight value will be overridden by the value from the DNS record.', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + }, + description: + 'A target is an ip address/hostname with a port that identifies an instance of a backend service. Every upstream can have many targets, and the targets can be dynamically added. Changes are effectuated on the fly.\n\nBecause the upstream maintains a history of target changes, the targets cannot be deleted or modified. To disable a target, post a new one with `weight=0;` alternatively, use the `DELETE` convenience method to accomplish the same.\n\nThe current target object definition is the one with the latest `created_at`.', + }, + UpstreamRequest: { + title: 'Upstream Request', + type: 'object', + properties: { + host_header: { + type: 'string', + description: + 'The hostname to be used as Host header when proxying requests through Kong.', + }, + algorithm: { + type: 'string', + default: 'round-robin', + description: 'Which load balancing algorithm to use.', + enum: ['round-robin', 'consistent-hashing', 'least-connections'], + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + healthchecks: { + $ref: '#/components/schemas/Healthcheck', + }, + slots: { + type: 'number', + default: 10000, + description: 'The number of slots in the loadbalancer algorithm (10-65536).', + }, + hash_on_cookie: { + type: 'string', + description: + 'The cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.', + }, + hash_on_cookie_path: { + type: 'string', + default: '/', + description: + 'The cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie.', + }, + hash_fallback_header: { + type: 'string', + description: + 'The header name to take the value from as hash input. Only required when hash_fallback is set to header.', + }, + hash_fallback: { + type: 'string', + default: 'none', + description: + 'What to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). One of: none, consumer, ip, header, or cookie. Not available if hash_on is set to cookie.', + enum: ['none', 'consumer', 'ip', 'header', 'cookie'], + }, + hash_on_header: { + type: 'string', + description: + 'The header name to take the value from as hash input. Only required when hash_on is set to header.', + }, + hash_on: { + type: 'string', + default: 'none', + description: + 'What to use as hashing input: none (resulting in a weighted-round-robin scheme with no hashing), consumer, ip, header, or cookie.', + enum: ['none', 'consumer', 'ip', 'header', 'cookie'], + }, + name: { + type: 'string', + }, + }, + required: ['name'], + 'x-examples': { + Entity: { + name: 'my-upstream', + tags: ['user-level', 'low-priority'], + }, + }, + description: '', + }, + SNIRequest: { + title: 'SNI Request', + type: 'object', + properties: { + tags: { + $ref: '#/components/schemas/Tags', + }, + certificate: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'uuid', + description: + 'The id (a UUID) of the certificate with which to associate the SNI hostname.', + }, + name: { + type: 'string', + }, + }, + }, + name: { + type: 'string', + description: + 'The SNI name to associate with the given certificate. May contain a single wildcard in the leftmost (suffix) or rightmost (prefix) position. This can be helpful when maintaining multiple subdomains, as a single SNI configured with a wildcard name can be used to match multiple subdomains, instead of creating an SNI entity for each. Valid wildcard positions are mydomain.*, *.mydomain.com, and *.www.mydomain.com. Plain SNI names (no wildcard) take priority when matching, followed by prefix and then suffix.', + }, + }, + 'x-examples': { + Request: { + name: 'my-sni', + certificate: { + id: 'a2e013e8-7623-4494-a347-6d29108ff68b', + }, + tags: ['user-level', 'low-priority'], + }, + }, + description: 'Create / Update SNI', + }, + UpstreamsResponse: { + title: 'UpstreamsResponse', + type: 'object', + description: 'Paginated list of Upstream entities', + properties: { + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Upstream', + }, + }, + offset: { + type: 'string', + }, + next: { + type: 'string', + }, + }, + 'x-examples': { + 'Response Body': { + data: [ + { + id: 'a2e013e8-7623-4494-a347-6d29108ff68b', + created_at: 1422386534, + name: 'my-upstream', + hash_on: 'none', + hash_fallback: 'none', + hash_on_cookie_path: '/', + slots: 10000, + healthchecks: { + active: { + https_verify_certificate: true, + unhealthy: { + http_statuses: [429, 404, 500, 501, 502, 503, 504, 505], + tcp_failures: 0, + timeouts: 0, + http_failures: 0, + interval: 0, + }, + http_path: '/', + timeout: 1, + healthy: { + http_statuses: [200, 302], + interval: 0, + successes: 0, + }, + https_sni: 'example.com', + concurrency: 10, + type: 'http', + }, + passive: { + unhealthy: { + http_failures: 0, + http_statuses: [429, 500, 503], + tcp_failures: 0, + timeouts: 0, + }, + type: 'http', + healthy: { + successes: 0, + http_statuses: [ + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + ], + }, + }, + }, + tags: ['user-level', 'low-priority'], + }, + { + id: '147f5ef0-1ed6-4711-b77f-489262f8bff7', + created_at: 1422386534, + name: 'my-upstream', + hash_on: 'none', + hash_fallback: 'none', + hash_on_cookie_path: '/', + slots: 10000, + healthchecks: { + active: { + https_verify_certificate: true, + unhealthy: { + http_statuses: [429, 404, 500, 501, 502, 503, 504, 505], + tcp_failures: 0, + timeouts: 0, + http_failures: 0, + interval: 0, + }, + http_path: '/', + timeout: 1, + healthy: { + http_statuses: [200, 302], + interval: 0, + successes: 0, + }, + https_sni: 'example.com', + concurrency: 10, + type: 'http', + }, + passive: { + unhealthy: { + http_failures: 0, + http_statuses: [429, 500, 503], + tcp_failures: 0, + timeouts: 0, + }, + type: 'http', + healthy: { + successes: 0, + http_statuses: [ + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + ], + }, + }, + }, + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: 'http://localhost:8001/upstreams?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + Upstream: { + title: 'Upstream Entity', + type: 'object', + 'x-examples': { + Entity: { + id: '91020192-062d-416f-a275-9addeeaffaf2', + created_at: 1422386534, + name: 'my-upstream', + algorithm: 'round-robin', + hash_on: 'none', + hash_fallback: 'none', + hash_on_cookie_path: '/', + slots: 10000, + healthchecks: { + active: { + https_verify_certificate: true, + unhealthy: { + http_statuses: [429, 404, 500, 501, 502, 503, 504, 505], + tcp_failures: 0, + timeouts: 0, + http_failures: 0, + interval: 0, + }, + http_path: '/', + timeout: 1, + healthy: { + http_statuses: [200, 302], + interval: 0, + successes: 0, + }, + https_sni: 'example.com', + concurrency: 10, + type: 'http', + }, + passive: { + unhealthy: { + http_failures: 0, + http_statuses: [429, 500, 503], + tcp_failures: 0, + timeouts: 0, + }, + type: 'http', + healthy: { + successes: 0, + http_statuses: [ + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 226, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + ], + }, + }, + }, + host_header: 'example.com', + tags: ['user-level', 'low-priority'], + }, + }, + description: + 'The upstream object represents a virtual hostname and can be used to loadbalance incoming requests over multiple services (targets). So for example an upstream named `service.v1.xyz` for a Service object whose host is `service.v1.xyz`. Requests for this Service would be proxied to the targets defined within the upstream.', + properties: { + id: { + type: 'string', + description: 'This is a hostname, which must be equal to the host of a Service.', + format: 'uuid', + }, + created_at: { + type: 'number', + }, + name: { + type: 'string', + }, + hash_on: { + type: 'string', + default: 'none', + description: + 'What to use as hashing input: none (resulting in a weighted-round-robin scheme with no hashing), consumer, ip, header, or cookie.', + enum: ['none', 'consumer', 'ip', 'header', 'cookie'], + }, + hash_on_header: { + type: 'string', + description: + 'The header name to take the value from as hash input. Only required when hash_on is set to header.', + }, + hash_fallback: { + type: 'string', + default: 'none', + description: + 'What to use as hashing input if the primary hash_on does not return a hash (eg. header is missing, or no consumer identified). One of: none, consumer, ip, header, or cookie. Not available if hash_on is set to cookie.', + enum: ['none', 'consumer', 'ip', 'header', 'cookie'], + }, + hash_fallback_header: { + type: 'string', + description: + 'The header name to take the value from as hash input. Only required when hash_fallback is set to header.', + }, + hash_on_cookie_path: { + type: 'string', + default: '/', + description: + 'The cookie path to set in the response headers. Only required when hash_on or hash_fallback is set to cookie.', + }, + hash_on_cookie: { + type: 'string', + description: + 'The cookie name to take the value from as hash input. Only required when hash_on or hash_fallback is set to cookie. If the specified cookie is not in the request, Kong will generate a value and set the cookie in the response.', + }, + slots: { + type: 'number', + default: 10000, + description: 'The number of slots in the loadbalancer algorithm (10-65536).', + }, + healthchecks: { + $ref: '#/components/schemas/Healthcheck', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + algorithm: { + type: 'string', + default: 'round-robin', + description: 'Which load balancing algorithm to use.', + enum: ['round-robin', 'consistent-hashing', 'least-connections'], + }, + host_header: { + type: 'string', + description: + 'The hostname to be used as Host header when proxying requests through Kong.', + }, + }, + required: ['name'], + }, + HealthcheckHealthy: { + title: 'HealthcheckHealthy', + type: 'object', + properties: { + http_statuses: { + type: 'array', + default: [200, 302], + description: + 'An array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks.', + items: { + type: 'number', + }, + }, + interval: { + type: 'number', + description: + 'Interval between active health checks for healthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed.', + }, + successes: { + type: 'number', + description: 'Number of successes to consider a target healthy.', + }, + }, + }, + HealthcheckUnhealthy: { + title: 'HealthcheckUnhealthy', + type: 'object', + properties: { + tcp_failures: { + type: 'number', + default: 0, + description: 'Number of TCP failures in active probes to consider a target unhealthy.', + }, + http_failures: { + type: 'number', + default: 0, + description: 'Number of HTTP failures in to consider a target unhealthy.', + }, + timeouts: { + type: 'number', + default: 0, + description: 'Number of timeouts in active probes to consider a target unhealthy.', + }, + http_statuses: { + type: 'array', + default: [429, 404, 500, 501, 502, 503, 504, 505], + description: + 'An array of HTTP statuses to consider a failure, indicating unhealthiness.', + items: { + type: 'number', + }, + }, + interval: { + type: 'number', + default: 0, + description: + 'Interval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for unhealthy targets should not be performed.', + }, + }, + }, + Healthcheck: { + title: 'Healthcheck', + type: 'object', + properties: { + active: { + type: 'object', + properties: { + https_verify_certificate: { + type: 'boolean', + default: true, + description: + 'Whether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS.', + }, + http_path: { + type: 'string', + default: '/', + description: + 'Path to use in GET HTTP request to run as a probe on active health checks.', + }, + timeout: { + type: 'number', + default: 1, + description: 'Socket timeout for active health checks (in seconds).', + }, + https_sni: { + type: 'string', + description: + 'The hostname to use as an SNI (Server Name Identification) when performing active health checks using HTTPS. This is particularly useful when Targets are configured using IPs, so that the target host’s certificate can be verified with the proper SNI.', + }, + concurrency: { + type: 'number', + default: 10, + description: 'Number of targets to check concurrently in active health checks.', + }, + type: { + type: 'string', + default: 'http', + description: + 'Whether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection. Possible values are tcp, http or https.', + enum: ['tcp', 'http', 'https'], + }, + unhealthy: { + $ref: '#/components/schemas/HealthcheckUnhealthy', + }, + healthy: { + $ref: '#/components/schemas/HealthcheckHealthy', + }, + }, + }, + passive: { + type: 'object', + properties: { + type: { + type: 'string', + default: 'http', + description: + 'Whether to perform passive health checks interpreting HTTP/HTTPS statuses, or just check for TCP connection success.', + enum: ['tcp', 'http', 'https'], + }, + unhealthy: { + $ref: '#/components/schemas/HealthcheckUnhealthy', + }, + healthy: { + $ref: '#/components/schemas/HealthcheckHealthy', + }, + }, + }, + }, + }, + SNISResponse: { + title: 'SNIs Response', + type: 'object', + description: 'Paginated list of SNI entities', + properties: { + next: { + type: 'string', + }, + offset: { + type: 'string', + }, + data: { + type: 'array', + items: { + $ref: '#/components/schemas/SNI', + }, + }, + }, + 'x-examples': { + 'Response Body': { + data: [ + { + id: 'a9b2107f-a214-47b3-add4-46b942187924', + name: 'my-sni', + created_at: 1422386534, + tags: ['user-level', 'low-priority'], + certificate: { + id: '04fbeacf-a9f1-4a5d-ae4a-b0407445db3f', + }, + }, + { + id: '43429efd-b3a5-4048-94cb-5cc4029909bb', + name: 'my-sni', + created_at: 1422386534, + tags: ['admin', 'high-priority', 'critical'], + certificate: { + id: 'd26761d5-83a4-4f24-ac6c-cff276f2b79c', + }, + }, + ], + next: 'http://localhost:8001/snis?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + CertificatesResponse: { + title: 'Certificates Response', + type: 'object', + properties: { + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Certificate', + }, + }, + offset: { + type: 'string', + }, + next: { + type: 'string', + }, + }, + 'x-examples': { + 'Response Body': { + data: [ + { + id: '02621eee-8309-4bf6-b36b-a82017a5393e', + created_at: 1422386534, + cert: '-----BEGIN CERTIFICATE-----...', + key: '-----BEGIN RSA PRIVATE KEY-----...', + tags: ['user-level', 'low-priority'], + }, + { + id: '66c7b5c4-4aaf-4119-af1e-ee3ad75d0af4', + created_at: 1422386534, + cert: '-----BEGIN CERTIFICATE-----...', + key: '-----BEGIN RSA PRIVATE KEY-----...', + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: 'http://localhost:8001/certificates?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + description: 'Paginated list of Certificate entities', + }, + CertificateRequest: { + title: 'CertificateRequest', + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, + ServicesResponse: { + title: 'Services Response', + type: 'object', + description: 'Paginated list of Service entities', + properties: { + next: { + type: 'string', + }, + offset: { + type: 'string', + }, + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Service', + }, + }, + }, + 'x-examples': { + 'Response Body': { + data: [ + { + id: '4e3ad2e4-0bc4-4638-8e34-c84a417ba39b', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/some_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['user-level', 'low-priority'], + }, + { + id: 'a5fb8d9b-a99d-40e9-9d35-72d42a62d83a', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-service', + retries: 5, + protocol: 'http', + host: 'example.com', + port: 80, + path: '/another_api', + connect_timeout: 60000, + write_timeout: 60000, + read_timeout: 60000, + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: 'http://localhost:8001/services?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + ConsumersResponse: { + title: 'Consumers Response', + type: 'object', + 'x-examples': { + 'Response Body': { + data: [ + { + id: '9aa116fd-ef4a-4efa-89bf-a0b17c4be982', + created_at: 1422386534, + username: 'my-username', + custom_id: 'my-custom-id', + tags: ['user-level', 'low-priority'], + }, + { + id: 'ba641b07-e74a-430a-ab46-94b61e5ea66b', + created_at: 1422386534, + username: 'my-username', + custom_id: 'my-custom-id', + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: 'http://localhost:8001/consumers?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + description: 'Paginated list of Consumer entities', + properties: { + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Consumer', + }, + }, + offset: { + type: 'string', + }, + next: { + type: 'string', + }, + }, + }, + Tags: { + title: 'Tags', + type: 'array', + items: { + 'x-examples': {}, + description: 'Individual tag value', + pattern: '^[A-Za-z-_\\.~]+$', + title: 'Tag', + type: 'string', + }, + description: 'List of tag values', + 'x-examples': {}, + }, + ConsumerRequest: { + title: 'Consumer Request', + type: 'object', + description: 'Create / Update Request Entity', + properties: { + username: { + type: 'string', + }, + custom_id: { + type: 'string', + }, + tags: { + type: 'array', + items: { + $ref: '#/components/schemas/Tag', + }, + }, + }, + 'x-examples': { + Request: { + username: 'my-username', + custom_id: 'my-custom-id', + tags: ['user-level', 'low-priority'], + }, + }, + }, + Tag: { + type: 'string', + title: 'Tag', + pattern: '^[A-Za-z-_\\.~]+$', + description: 'Individual tag value', + 'x-examples': {}, + }, + PluginsResponse: { + title: 'PluginsResponse', + type: 'object', + description: 'Paginated List of Plugin entities', + 'x-examples': { + 'Response Body': { + data: [ + { + id: 'a4407883-c166-43fd-80ca-3ca035b0cdb7', + name: 'rate-limiting', + created_at: 1422386534, + route: null, + service: null, + consumer: null, + config: { + hour: 500, + minute: 20, + }, + run_on: 'first', + protocols: ['http', 'https'], + enabled: true, + tags: ['user-level', 'low-priority'], + }, + { + id: '01c23299-839c-49a5-a6d5-8864c09184af', + name: 'rate-limiting', + created_at: 1422386534, + route: null, + service: null, + consumer: null, + config: { + hour: 500, + minute: 20, + }, + run_on: 'first', + protocols: ['tcp', 'tls'], + enabled: true, + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: 'http://localhost:8001/plugins?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + properties: { + next: { + type: 'string', + }, + offset: { + type: 'string', + }, + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Plugin', + }, + }, + }, + }, + PluginRequest: { + title: 'Plugin Request', + type: 'object', + properties: { + tags: { + $ref: '#/components/schemas/Tags', + }, + enabled: { + type: 'boolean', + description: 'Whether the plugin is applied to matching requests.', + default: true, + }, + protocols: { + type: 'array', + enum: ['http', 'https'], + items: { + type: 'string', + }, + }, + run_on: { + type: 'string', + enum: ['first', 'second', 'all'], + description: + 'Control on which Kong nodes this plugin will run, given a Service Mesh scenario.', + default: 'first', + }, + config: { + type: 'object', + description: + 'The configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.', + }, + consumer: { + type: 'object', + description: + 'If set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer.', + default: null, + properties: { + id: { + type: 'string', + format: 'uuid', + }, + name: { + type: 'string', + }, + }, + }, + service: { + type: 'object', + description: + 'If set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched.', + default: null, + properties: { + id: { + type: 'string', + format: 'uuid', + }, + name: { + type: 'string', + }, + }, + }, + route: { + type: 'object', + description: + 'If set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used.', + default: null, + properties: { + id: { + type: 'string', + format: 'uuid', + }, + name: { + type: 'string', + }, + }, + }, + name: { + type: 'string', + pattern: '^[A-Za-z-_]+$', + description: + 'The name of the Plugin that’s going to be added. The Plugin must be installed in every Kong instance in the cluster.', + }, + }, + 'x-examples': { + REQUEST: { + name: 'rate-limiting', + config: { + hour: 500, + minute: 20, + }, + tags: ['user-level', 'low-priority'], + }, + }, + description: 'Create / Update Request', + }, + RoutesResponse: { + title: 'Routes Response', + type: 'object', + 'x-examples': { + 'Response Body': { + data: [ + { + id: '4506673d-c825-444c-a25b-602e3c2ec16e', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + { + id: 'af8330d3-dbdc-48bd-b1be-55b98608834b', + created_at: 1422386534, + updated_at: 1422386534, + name: 'my-route', + protocols: ['tcp', 'tls'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + snis: ['foo.test', 'example.com'], + sources: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + destinations: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + tags: ['admin', 'high-priority', 'critical'], + service: { + id: 'a9daa3ba-8186-4a0d-96e8-00d80ce7240b', + }, + }, + ], + next: 'http://localhost:8001/routes?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + properties: { + data: { + type: 'array', + items: { + $ref: '#/components/schemas/Route', + }, + }, + offset: { + type: 'string', + }, + next: { + type: 'string', + }, + }, + description: 'Paginated list of route entities', + }, + Plugin: { + title: 'Plugin Entity', + type: 'object', + description: + 'A Plugin entity represents a plugin configuration that will be executed during the HTTP request/response lifecycle. Plugins apply additional functionalities and policies such as Rate Limiting / Authentication to incoming requests to Kong.', + 'x-examples': { + Entity: { + id: 'ec1a1f6f-2aa4-4e58-93ff-b56368f19b27', + name: 'rate-limiting', + created_at: 1422386534, + route: null, + service: null, + consumer: null, + config: { + hour: 500, + minute: 20, + }, + run_on: 'first', + protocols: ['http', 'https'], + enabled: true, + tags: ['user-level', 'low-priority'], + }, + }, + properties: { + id: { + type: 'string', + format: 'uuid', + }, + name: { + type: 'string', + description: + 'The name of the Plugin that’s going to be added. The Plugin must be installed in every Kong instance in the cluster.', + pattern: '^[A-Za-z-_]+$', + }, + route: { + type: 'object', + default: null, + description: + 'If set, the plugin will only activate when receiving requests via the specified route. Leave unset for the plugin to activate regardless of the Route being used.', + properties: { + id: { + type: 'string', + format: 'uuid', + }, + }, + }, + service: { + type: 'object', + default: null, + description: + 'If set, the plugin will only activate when receiving requests via one of the routes belonging to the specified Service. Leave unset for the plugin to activate regardless of the Service being matched.', + properties: { + id: { + type: 'string', + format: 'uuid', + }, + }, + }, + consumer: { + type: 'object', + default: null, + description: + 'If set, the plugin will activate only for requests where the specified has been authenticated. (Note that some plugins can not be restricted to consumers this way.). Leave unset for the plugin to activate regardless of the authenticated consumer.', + properties: { + id: { + type: 'string', + format: 'uuid', + }, + }, + }, + config: { + type: 'object', + description: + 'The configuration properties for the Plugin which can be found on the plugins documentation page in the Kong Hub.', + }, + run_on: { + type: 'string', + default: 'first', + description: + 'Control on which Kong nodes this plugin will run, given a Service Mesh scenario.', + enum: ['first', 'second', 'all'], + }, + protocols: { + type: 'array', + enum: ['http', 'https'], + items: { + type: 'string', + }, + }, + enabled: { + type: 'boolean', + default: true, + description: 'Whether the plugin is applied to matching requests.', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + created_at: { + type: 'number', + }, + }, + required: ['name'], + }, + RouteRequest: { + title: 'RouteRequest', + type: 'object', + description: 'Request body to create a Route entity', + 'x-examples': { + HOSTS: { + name: 'my-route', + protocols: ['http', 'https'], + methods: ['GET', 'POST'], + hosts: ['example.com', 'foo.test'], + paths: ['/foo', '/bar'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + tags: ['user-level', 'low-priority'], + service: { + id: 'd35165e2-d03e-461a-bdeb-dad0a112abfe', + }, + }, + SNIS: { + name: 'my-route', + protocols: ['tcp', 'tls'], + https_redirect_status_code: 426, + regex_priority: 0, + strip_path: true, + preserve_host: false, + snis: ['foo.test', 'example.com'], + sources: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + destinations: [ + { + ip: '10.1.0.0/16', + port: 1234, + }, + { + ip: '10.2.2.2', + }, + { + port: 9123, + }, + ], + tags: ['admin', 'high-priority', 'critical'], + service: { + name: 'my-name', + }, + }, + }, + properties: { + destinations: { + type: 'array', + description: + 'A list of IP destinations of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + items: { + type: 'string', + }, + }, + sources: { + description: + 'A list of IP sources of incoming connections that match this Route when using stream routing. Each entry is an object with fields “ip” (optionally in CIDR range notation) and/or “port”. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + type: 'array', + items: { + type: 'string', + }, + }, + snis: { + description: + 'A list of SNIs that match this Route when using stream routing. When using tcp or tls protocols, at least one of snis, sources, or destinations must be set.', + type: 'array', + items: { + type: 'string', + }, + }, + name: { + type: 'string', + pattern: '^[a-z-_]+', + example: 'my-route', + description: 'The name of the Route.', + }, + protocols: { + type: 'array', + default: ['http', 'https'], + description: 'A list of the protocols this Route should allow.', + enum: ['http', 'https'], + items: { + type: 'string', + }, + }, + methods: { + type: 'array', + description: 'A list of HTTP methods that match this Route.', + items: { + type: 'string', + }, + }, + hosts: { + type: 'array', + description: 'A list of domain names that match this Route.', + items: { + type: 'string', + }, + }, + paths: { + type: 'array', + description: 'A list of paths that match this Route.', + items: { + type: 'string', + }, + }, + https_redirect_status_code: { + type: 'integer', + default: 426, + description: + 'The status code Kong responds with when all properties of a Route match except the protocol', + example: 426, + }, + regex_priority: { + type: 'integer', + default: 0, + description: + 'A number used to choose which route resolves a given request when several routes match it using regexes simultaneously. When two routes match the path and have the same regex_priority, the older one (lowest created_at) is used.', + example: 0, + }, + strip_path: { + type: 'boolean', + default: true, + description: + 'When matching a Route via one of the paths, strip the matching prefix from the upstream request URL. ', + example: true, + }, + preserve_host: { + type: 'boolean', + example: false, + description: + 'When matching a Route via one of the hosts domain names, use the request Host header in the upstream request headers.', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + service: { + type: 'object', + description: 'The Service this Route is associated to (by either id or name).', + properties: { + id: { + type: 'string', + example: 'fc73f2af-890d-4f9b-8363-af8945001f7f', + description: 'Service Identifier', + }, + name: { + type: 'string', + description: 'Service Name', + }, + }, + }, + }, + }, + Consumer: { + title: 'Consumer Entity', + type: 'object', + description: 'The Consumer object represents a consumer - or a user - of a Service.', + 'x-examples': { + Entity: { + id: '127dfc88-ed57-45bf-b77a-a9d3a152ad31', + created_at: 1422386534, + username: 'my-username', + custom_id: 'my-custom-id', + tags: ['user-level', 'low-priority'], + }, + }, + properties: { + id: { + type: 'string', + }, + created_at: { + type: 'number', + }, + username: { + type: 'string', + }, + custom_id: { + type: 'string', + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + }, + }, + SNI: { + title: 'SNI Entity', + type: 'object', + 'x-examples': { + Entity: { + id: '7fca84d6-7d37-4a74-a7b0-93e576089a41', + name: 'my-sni', + created_at: 1422386534, + tags: ['user-level', 'low-priority'], + certificate: { + id: 'd044b7d4-3dc2-4bbc-8e9f-6b7a69416df6', + }, + }, + }, + description: + 'An SNI object represents a many-to-one mapping of hostnames to a certificate. That is, a certificate object can have many hostnames associated with it; when Kong receives an SSL request, it uses the SNI field in the Client Hello to lookup the certificate object based on the SNI associated with the certificate.', + properties: { + id: { + type: 'string', + }, + name: { + type: 'string', + description: + 'The SNI name to associate with the given certificate. May contain a single wildcard in the leftmost (suffix) or rightmost (prefix) position. This can be helpful when maintaining multiple subdomains, as a single SNI configured with a wildcard name can be used to match multiple subdomains, instead of creating an SNI entity for each. Valid wildcard positions are mydomain.*, *.mydomain.com, and *.www.mydomain.com. Plain SNI names (no wildcard) take priority when matching, followed by prefix and then suffix.', + }, + created_at: { + type: 'number', + }, + certificate: { + type: 'object', + properties: { + id: { + type: 'string', + format: 'uuid', + description: + 'The id (a UUID) of the certificate with which to associate the SNI hostname.', + }, + }, + }, + tags: { + $ref: '#/components/schemas/Tags', + }, + }, + }, + Workspace: { + title: 'Workspace', + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, + UpstreamTargetResponse: { + title: 'Upstream Targets Response', + type: 'object', + properties: { + next: { + type: 'string', + }, + offset: { + type: 'string', + }, + data: { + type: 'array', + items: { + $ref: '#/components/schemas/UpstreamTarget', + }, + }, + }, + description: 'Response body for lists', + 'x-examples': { + Response: { + data: [ + { + id: 'f5a9c0ca-bdbb-490f-8928-2ca95836239a', + created_at: 1422386534, + upstream: { + id: '173a6cee-90d1-40a7-89cf-0329eca780a6', + }, + target: 'example.com:8000', + weight: 100, + tags: ['user-level', 'low-priority'], + }, + { + id: 'bdab0e47-4e37-4f0b-8fd0-87d95cc4addc', + created_at: 1422386534, + upstream: { + id: 'f00c6da4-3679-4b44-b9fb-36a19bd3ae83', + }, + target: 'example.com:8000', + weight: 100, + tags: ['admin', 'high-priority', 'critical'], + }, + ], + next: + 'http://localhost:8001/upstream/example.com:8000/targets?offset=6378122c-a0a1-438d-a5c6-efabae9fb969', + }, + }, + }, + UpstreamTargetRequest: { + title: 'Upstream Target Request', + type: 'object', + properties: { + tags: { + $ref: '#/components/schemas/Tags', + }, + weight: { + type: 'integer', + default: 100, + description: + 'The weight this target gets within the upstream loadbalancer (`0`-`1000`). If the hostname resolves to an SRV record, the weight value will be overridden by the value from the DNS record.', + }, + target: { + type: 'string', + description: + 'The target address (ip or hostname) and port. If the hostname resolves to an SRV record, the port value will be overridden by the value from the DNS record.', + }, + }, + 'x-examples': { + Request: { + target: 'example.com:8000', + weight: 100, + tags: ['user-level', 'low-priority'], + }, + }, + description: 'Create / Update request body', + }, + }, + securitySchemes: { + 'Kong-Admin-Token': { + name: 'Kong-Admin-Token', + type: 'apiKey', + in: 'header', + description: 'Kong Admin RBAC Token\n', + }, + }, + callbacks: {}, + links: {}, + headers: { + 'X-RateLimit-Limit': { + description: 'Request limit per hour', + schema: { + type: 'integer', + }, + }, + 'X-RateLimit-Remaining': { + description: 'The number of requests left for the time window', + schema: { + type: 'integer', + }, + }, + 'X-RateLimit-Reset': { + description: 'UTC date/time at which the current rate limit resets', + schema: { + type: 'integer', + }, + }, + }, + parameters: { + skipParam: { + name: 'skip', + in: 'query', + description: 'number of items to skip', + required: true, + schema: { + type: 'integer', + format: 'int32', + }, + }, + limitParam: { + name: 'limit', + in: 'query', + description: 'max records to return', + required: true, + schema: { + type: 'integer', + format: 'int32', + }, + }, + }, + responses: { + NotFound: { + description: 'Entity not found.', + }, + IllegalInput: { + description: 'Illegal input for operation.', + }, + GeneralError: { + description: 'General Error', + content: { + 'application/json': { + schema: { + $ref: '#/components/schemas/GeneralError', + }, + }, + }, + }, + }, + }, + security: [], +}; + +export const _default = () => ( +
+ +
+); + +_default.story = { + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/sS7oBbKmDvhtq5lXyTckVe/Style-Guide-Components?node-id=0%3A2', + }, + }, +}; diff --git a/packages/insomnia-components/components/svg-icon.js b/packages/insomnia-components/components/svg-icon.js index ce1fc681c..3ff5e923c 100644 --- a/packages/insomnia-components/components/svg-icon.js +++ b/packages/insomnia-components/components/svg-icon.js @@ -43,6 +43,8 @@ import MemoSvgIcnUser from '../assets/svgr/IcnUser'; import MemoSvgIcnWarningCircle from '../assets/svgr/IcnWarningCircle'; import MemoSvgIcnX from '../assets/svgr/IcnX'; import MemoSvgIcnInfo from '../assets/svgr/IcnInfo'; +import MemoSvgIcnKey from '../assets/svgr/IcnKey'; +import MemoSvgIcnBrackets from '../assets/svgr/IcnBrackets'; export const ThemeEnum = { default: 'default', @@ -101,6 +103,8 @@ export const IconEnum = { user: 'user', warningCircle: 'warning-circle', x: 'x', + key: 'key', + brackets: 'brackets', // Blank icon empty: 'empty', @@ -190,6 +194,8 @@ class SvgIcon extends React.Component { [IconEnum.user]: [ThemeEnum.default, MemoSvgIcnUser], [IconEnum.warningCircle]: [ThemeEnum.default, MemoSvgIcnWarningCircle], [IconEnum.x]: [ThemeEnum.default, MemoSvgIcnX], + [IconEnum.key]: [ThemeEnum.default, MemoSvgIcnKey], + [IconEnum.brackets]: [ThemeEnum.default, MemoSvgIcnBrackets], }; render() { diff --git a/packages/insomnia-components/flow-typed/react-use.js b/packages/insomnia-components/flow-typed/react-use.js new file mode 100644 index 000000000..1190c691c --- /dev/null +++ b/packages/insomnia-components/flow-typed/react-use.js @@ -0,0 +1,7 @@ +// @flow + +import * as React from 'react'; + +declare module 'react-use' { + declare module.exports: *; +} diff --git a/packages/insomnia-components/index.js b/packages/insomnia-components/index.js index 346cee34c..29ed238ea 100644 --- a/packages/insomnia-components/index.js +++ b/packages/insomnia-components/index.js @@ -9,9 +9,9 @@ import _GravatarImg from './components/gravatar-img'; import _Header from './components/header'; import _MultiSwitch from './components/multi-switch'; import _NoticeTable from './components/notice-table'; -import _RadioButtonGroup from './components/radio-button-group'; -import _Sidebar from './components/sidebar'; import _SvgIcon from './components/svg-icon'; +import _Sidebar from './components/sidebar/'; +import _RadioButtonGroup from './components/radio-button-group'; import _Switch from './components/switch'; import _ToggleSwitch from './components/toggle-switch'; import * as table from './components/table'; diff --git a/packages/insomnia-components/package-lock.json b/packages/insomnia-components/package-lock.json index 4a5a6a6c5..5f0d5bc7f 100644 --- a/packages/insomnia-components/package-lock.json +++ b/packages/insomnia-components/package-lock.json @@ -2848,6 +2848,12 @@ "integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==", "dev": true }, + "@types/js-cookie": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.6.tgz", + "integrity": "sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw==", + "dev": true + }, "@types/npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.2.tgz", @@ -3100,6 +3106,12 @@ "@xtuc/long": "4.2.2" } }, + "@xobotyi/scrollbar-width": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz", + "integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==", + "dev": true + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4206,6 +4218,12 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==", + "dev": true + }, "boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -5263,6 +5281,24 @@ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" }, + "css-in-js-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz", + "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", + "dev": true, + "requires": { + "hyphenate-style-name": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "css-loader": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", @@ -5866,6 +5902,15 @@ "is-arrayish": "^0.2.1" } }, + "error-stack-parser": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", + "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, "es-abstract": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", @@ -6313,6 +6358,18 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fast-shallow-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz", + "integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==", + "dev": true + }, + "fastest-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-1.0.1.tgz", + "integrity": "sha1-kSLUBtTJ2YvqZEpraFPVh0uHsCg=", + "dev": true + }, "fault": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", @@ -7808,6 +7865,12 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "hyphenate-style-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", + "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -7950,6 +8013,16 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "inline-style-prefixer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-4.0.2.tgz", + "integrity": "sha512-N8nVhwfYga9MiV9jWlwfdj1UDIaZlBFu4cJSJkIr7tZX7sHpHhGR5su1qdpW+7KPL8ISTvCIkcaFi/JdBknvPg==", + "dev": true, + "requires": { + "bowser": "^1.7.3", + "css-in-js-utils": "^2.0.0" + } + }, "inquirer": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", @@ -8458,6 +8531,12 @@ } } }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", + "dev": true + }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -9189,6 +9268,30 @@ "dev": true, "optional": true }, + "nano-css": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.3.0.tgz", + "integrity": "sha512-uM/9NGK9/E9/sTpbIZ/bQ9xOLOIHZwrrb/CRlbDHBU/GFS7Gshl24v/WJhwsVViWkpOXUmiZ66XO7fSB4Wd92Q==", + "dev": true, + "requires": { + "css-tree": "^1.0.0-alpha.28", + "csstype": "^2.5.5", + "fastest-stable-stringify": "^1.0.1", + "inline-style-prefixer": "^4.0.0", + "rtl-css-js": "^1.9.0", + "sourcemap-codec": "^1.4.1", + "stacktrace-js": "^2.0.0", + "stylis": "3.5.0" + }, + "dependencies": { + "stylis": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.0.tgz", + "integrity": "sha512-pP7yXN6dwMzAR29Q0mBrabPCe0/mNO1MSr93bhay+hcZondvMMTpeGyd8nbhYJdyperNT2DRxONQuUGcJr5iPw==", + "dev": true + } + } + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -10871,6 +10974,48 @@ "react-lifecycles-compat": "^3.0.4" } }, + "react-universal-interface": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz", + "integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==", + "dev": true + }, + "react-use": { + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/react-use/-/react-use-15.3.2.tgz", + "integrity": "sha512-DAbc+pVedZC4P5rLBKdIvTTB03+4T/pR6jZ2pKQPgqfq4UC1Oymmbehon5z8XXSUgZs0tgIvbBzVEdiWMS9k+g==", + "dev": true, + "requires": { + "@types/js-cookie": "2.2.6", + "@xobotyi/scrollbar-width": "1.9.5", + "copy-to-clipboard": "^3.2.0", + "fast-deep-equal": "^3.1.3", + "fast-shallow-equal": "^1.0.0", + "js-cookie": "^2.2.1", + "nano-css": "^5.2.1", + "react-universal-interface": "^0.6.2", + "resize-observer-polyfill": "^1.5.1", + "screenfull": "^5.0.0", + "set-harmonic-interval": "^1.0.1", + "throttle-debounce": "^2.1.0", + "ts-easing": "^0.2.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "tslib": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", + "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==", + "dev": true + } + } + }, "reactcss": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", @@ -11245,6 +11390,15 @@ "inherits": "^2.0.1" } }, + "rtl-css-js": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.14.0.tgz", + "integrity": "sha512-Dl5xDTeN3e7scU1cWX8c9b6/Nqz3u/HgR4gePc1kWXYiQWVQbKCEyK6+Hxve9LbcJ5EieHy1J9nJCN3grTtGwg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.1.2" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -11320,6 +11474,12 @@ "ajv-keywords": "^3.1.0" } }, + "screenfull": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.0.2.tgz", + "integrity": "sha512-cCF2b+L/mnEiORLN5xSAz6H3t18i2oHh9BA8+CQlAh5DRw2+NFAGQJOSYbcGw8B2k04g/lVvFcfZ83b3ysH5UQ==", + "dev": true + }, "select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", @@ -11430,6 +11590,12 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "set-harmonic-interval": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz", + "integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==", + "dev": true + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -11827,6 +11993,12 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "space-separated-tokens": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", @@ -11863,6 +12035,50 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "stack-generator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz", + "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", + "dev": true, + "requires": { + "stackframe": "^1.1.1" + } + }, + "stackframe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", + "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", + "dev": true + }, + "stacktrace-gps": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz", + "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", + "dev": true, + "requires": { + "source-map": "0.5.6", + "stackframe": "^1.1.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, + "stacktrace-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", + "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", + "dev": true, + "requires": { + "error-stack-parser": "^2.0.6", + "stack-generator": "^2.0.5", + "stacktrace-gps": "^3.0.4" + } + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -12453,6 +12669,12 @@ "integrity": "sha512-UGTRZu1evMw4uTPyYF66/KFd22XiU+jMaIuHrkIHQ2GivAXVlLV0v/vHrpOuTRf9BmpNHi/SO7Vd0rLu0y57jg==", "dev": true }, + "ts-easing": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz", + "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==", + "dev": true + }, "ts-pnp": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.5.tgz", diff --git a/packages/insomnia-components/package.json b/packages/insomnia-components/package.json index 498d73157..fc61df2a8 100644 --- a/packages/insomnia-components/package.json +++ b/packages/insomnia-components/package.json @@ -28,6 +28,7 @@ "babel-plugin-inline-react-svg": "^1.1.1", "react": "^16.8.6", "react-dom": "^16.8.6", + "react-use": "^15.3.2", "storybook-addon-designs": "^5.2.0", "webpack": "^4.42.1", "webpack-cli": "^3.3.11",