Merge pull request #27 from Bandwidth/sync

Sync Fork with Cherry-Pick
This commit is contained in:
Cameron Koegel 2023-11-01 13:07:54 -04:00 committed by GitHub
commit a2efa58031
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 7562 additions and 6624 deletions

View File

@ -1,11 +1,13 @@
# ReDoc Contributing Guide
# Redoc Contributing Guide
Hi! We're really excited that you are interested in contributing to ReDoc. This is the wrong place to do that if you don't work at Bandwidth :). Please contribute to [Redocly/redoc](https://github.com/Redocly/redoc) instead. If you are from Bandwidth, before submitting your contribution, please make sure to take a moment and read through the following guidelines.
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Development Setup](#development-setup)
- [Project Structure](#project-structure)
- [Redoc Contributing Guide](#redoc-contributing-guide)
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Development Setup](#development-setup)
- [Commonly used NPM scripts](#commonly-used-npm-scripts)
- [Project Structure](#project-structure)
## Issue Reporting Guidelines
- Before filing a new issue, try to make sure your problem doesnt already exist.
@ -22,7 +24,7 @@ Before submitting a pull request, please make sure the following is done:
## Development Setup
You will need [Node.js](http://nodejs.org) at `v12.0.0+`.
You need [Node.js](http://nodejs.org) at `v12.0.0+`.
After cloning the repo, run:
@ -88,7 +90,7 @@ There are some other scripts available in the `scripts` section of the `package.
- **`src/common-elements`**: contains common Styled elements or components used in multiple places
- **`src/components`**: contains main visual components
- **`src/services`**: contains different services used by ReDoc including MobX stores
- **`src/services`**: contains different services used by Redoc including MobX stores
- **`src/services/models`**: contains classes for OpenAPI entities (e.g. Response, Operations, etc)
- **`src/types`**: contains extra typescript typings including OpenAPI doc typings
- **`src/utils`**: utility functions

110
.github/styles/Rules/BritishEnglish.yml vendored Normal file
View File

@ -0,0 +1,110 @@
extends: substitution
message: 'Use the US spelling "%s" instead of British "%s".'
link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-us-spelling-avoid-non-english-words
level: error
ignorecase: true
swap:
aeon: eon
aeroplane: airplane
ageing: aging
aluminium: aluminum
anaemia: anemia
anaesthesia: anesthesia
analyse: analyze
annexe: annex
apologise: apologize
behaviour: behavior
busses: buses
calibre: caliber
cancelled: canceled
cancellation: cancelation
catalogue: catalog
categorise: categorize
categorised: categorized
categorises: categorizes
categorising: categorizing
centre: center
cheque: check
civilisation: civilization
civilise: civilize
colour: color
cosy: cozy
cypher: cipher
dependant: dependent
defence: defense
distil: distill
draught: draft
encyclopaedia: encyclopedia
enquiry: inquiry
enrol: enroll
enrolment: enrollment
enthral: enthrall
expiry: expiration
favourite: favorite
fibre: fiber
fillet: filet
flavour: flavor
furore: furor
fulfil: fulfill
gaol: jail
grey: gray
humour: humor
honour: honor
initialled: initialed
initialling: initialing
instil: instill
jewellery: jewelry
labelling: labeling
labelled: labeled
labour: labor
libellous: libelous
licence: license
likeable: likable
liveable: livable
lustre: luster
manoeuvre: maneuver
marvellous: marvelous
matt: matte
meagre: meager
metre: meter
modelling: modeling
moustache: mustache
neighbour: neighbor
normalise: normalize
offence: offense
organise: organize
organisation: organization
orientated: oriented
paralyse: paralyze
plough: plow
pretence: pretense
programme: program
pyjamas: pajamas
rateable: ratable
realise: realize
recognise: recognize
reconnoitre: reconnoiter
rumour: rumor
sabre: saber
saleable: salable
saltpetre: saltpeter
sceptic: skeptic
sepulchre: sepulcher
signalling: signaling
sizeable: sizable
skilful: skillful
sombre: somber
smoulder: smolder
speciality: specialty
spectre: specter
splendour: splendor
standardise: standardize
standardised: standardized
sulphur: sulfur
theatre: theater
travelled: traveled
traveller: traveler
travelling: traveling
unshakeable: unshakable
wilful: willful
yoghurt: yogurt

10
.github/styles/Rules/FutureTense.yml vendored Normal file
View File

@ -0,0 +1,10 @@
extends: existence
message: 'Avoid using future tense: "%s". Use present tense instead.'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#tone-and-audience
ignorecase: true
level: error
raw:
- "(going to( |\n|[[:punct:]])[a-zA-Z]*|"
- "will( |\n|[[:punct:]])[a-zA-Z]*|"
- "won't( |\n|[[:punct:]])[a-zA-Z]*|"
- "[a-zA-Z]*'ll( |\n|[[:punct:]])[a-zA-Z]*)"

11
.github/styles/Rules/HeaderGerunds.yml vendored Normal file
View File

@ -0,0 +1,11 @@
extends: existence
message: 'Do not start headings with with a gerund (ing word). Use an imperative verb instead.'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#content-organization
level: error
scope: heading
tokens:
- '^\w*ing.*'
exceptions:
- expandSingleSchemaField
- hideLoading
- hideSingleRequestSampleTab

View File

@ -0,0 +1,16 @@
extends: substitution
message: 'Use inclusive language. Consider "%s" instead of "%s".'
link: https://intranet.redoc.ly/contributing/documentation-style-guide/#grammar-and-syntax
level: error
ignorecase: true
swap:
he: they
his: their
she: they
hers: their
blacklist(?:ed|ing|s)?: blocklist
whitelist(?:ed|ing|s)?: allowlist
master: primary, main
slave: replica
he/she: they
s/he: they

8
.github/styles/Rules/OxfordComma.yml vendored Normal file
View File

@ -0,0 +1,8 @@
extends: existence
message: "Use the Oxford comma in '%s'."
link: https://docs.microsoft.com/en-us/style-guide/punctuation/commas
scope: sentence
level: error
nonword: true
tokens:
- '(?:[^\s,]+,){1,} \w+ (?:and|or) \w+[.?!]'

150
.github/styles/Vocab/Rules/accept.txt vendored Normal file
View File

@ -0,0 +1,150 @@
[Aa]nsible
[Aa]utostart
[Bb]locklist
[Bb]locklists
[Bb]oolean
[Bb]reakpoint
[B]reakpoints
[Cc]ancelation
[Cc]lassloading
[Cc]hargeback
[Cc]hargebacks
[Cc]he
[Cc]rypto
[Cc]ryptocurrency
[Dd]evfile|[Dd]evfiles
[Dd]ownstream
[Dd]ownstreaming
[Ff]actories|[Ff]actory
[Gg]it
[Gg]rafana
[Hh]eatmap
[Hh]elm
[Hh]ostname
[Ii]tem
[Jj]etbrains
[Kk]eycloak
[Ll]iveness
[Ll]ombok
[Ll]oopback
[Mm]aven
[Mm]inikube
[Mm]inishift
[Mm]ixin|[Mm]ixins
[Mm]odularization
[Mm]ulticluster
[Mm]ultihost
[Mm]ultinode
[Mm]ultitenant
[Mm]ultiuser
[Mm]ultizone
[Nn]amespace|[Nn]amespaces
[Nn]etcoredebug[Oo]utput
[Nn]ginx
[Oo]nboarding
[Pp]podman
[Pp]reconfigured
[Rr]eadonly
[Rr]epresentment
[Rr]ollout|[Rr]ollouts
[Rr]untime|[Rr]untimes
[Ss]erializer
[Ss]erverless
[Ss]ubnetwork
[Ss]ubpath|[Ss]ubpaths
[Tt]heia
[Tt]olerations
[Tt]ruststore
[Uu]ninstallation
[Uu]nstaged
[Uu]ntrusted
[Ww]orkspace|[Ww]orkspaces
[Yy]eoman
\.NET
adoc
Antora
API
Apigee
AsciiDoc
AWS|aws
Azure
Bierner
Bitbucket
btn
Btrfs
CentOS
Ceph
Che-Theia
CLI
ConfigMap|ConfigMaps
Ctrl
DaemonSet
Dev Workspace
Developer Perspective
DNS
Docker
Dockerfile
Dotnet
Endevor
endif
GitHub|github
GitLab
Gluster
Gradle
Grafana
GUI
HTTPS|https
I/O
IDE|ide|IDEs
Intelephense
IntelliJ IDEA
Java
Java Lombok
JSON|json
JVM|jvm
kbd
Kubespray
Laravel
Let\'s Encrypt
Mattermost
mebibytes
Microsoft Azure
millicores
Mulesoft
MySQL
Netlify
Node.js
npm
NuGet
OAuth
ocp
OmniSharp
OpenShift
OpenTracing
Operator
OperatorHub
OpenAPI
osd
PHP
PostgreSQL
Quarkus
Rebilly
Redoc
Redocly
Redocly-cli
SCM
Sharding
SonarLint
Spring Boot
SVG
Uber
URI|URIs
URL|url|URLs
Velero
Vercel
Visual Studio Code
vsix
Webview|Webviews
Woopra
YAML|yaml
Zowe

0
.github/styles/Vocab/Rules/reject.txt vendored Normal file
View File

16
.github/workflows/vale.yaml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Docs lint
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
vale:
name: vale action
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: errata-ai/vale-action@reviewdog
with:
files: '["README.md", "docs"]'
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

48
.vale.ini Normal file
View File

@ -0,0 +1,48 @@
# Vale configuration file.
# See: https://docs.errata.ai/vale/config
# The relative path to the folder containing linting rules (styles).
StylesPath = .github/styles
# Vocab define the exceptions to use in *all* `BasedOnStyles`.
# spelling-exceptions.txt triggers `Vale.Terms`
# reject.txt triggers `Vale.Avoid`
# See: https://docs.errata.ai/vale/vocab
Vocab = Rules
# Minimum alert level
# -------------------
# The minimum alert level in the output (suggestion, warning, or error).
# If integrated into CI, builds fail by default on error-level alerts, unless you run Vale with the --no-exit flag
MinAlertLevel = suggestion
# IgnoredScopes specifies inline-level HTML tags to ignore.
# These tags may occur in an active scope (unlike SkippedScopes, skipped entirely) but their content still won't raise any alerts.
# Default: ignore `code` and `tt`.
IgnoredScopes = code, tt, img, url, a, body.id
# SkippedScopes specifies block-level HTML tags to ignore. Ignore any content in these scopes.
# Default: ignore `script`, `style`, `pre`, and `figure`.
# For AsciiDoc: by default, listingblock, and literalblock.
SkippedScopes = script, style, pre, figure, code, tt, listingblock, literalblock
# Rules for matching file types. See: https://docs.errata.ai/vale/scoping
[formats]
properties = md
mdx = md
# Rules for .MD, .MDX
[*.{md,mdx}]
BasedOnStyles = Rules
# Ignore code surrounded by backticks or plus sign, parameters defaults, URLs.
TokenIgnores = (\x60[^\n\x60]+\x60), ([^\n]+=[^\n]*), (\+[^\n]+\+), (http[^\n]+\[)
Vale.Repetition = NO
Vale.SentenceSpacing = NO
Vale.Spelling = NO
# /End of rules for .MD, .MDX
# Process .ini files
[*.ini]

View File

@ -1,3 +1,62 @@
## [2.1.3](https://github.com/Redocly/redoc/compare/v2.1.2...v2.1.3) (2023-10-24)
### Bug Fixes
* default value as object in request body ([#2437](https://github.com/Redocly/redoc/issues/2437)) ([b36a6e2](https://github.com/Redocly/redoc/commit/b36a6e27bb3e03d39ee74c3e71f18a504539d91b))
* display string pattern in array items ([#2438](https://github.com/Redocly/redoc/issues/2438)) ([8ddeb6d](https://github.com/Redocly/redoc/commit/8ddeb6dfda686ec8a6948eb2d96efb99bf422429))
* hideRequestPayloadSample ([#2436](https://github.com/Redocly/redoc/issues/2436)) ([bf96061](https://github.com/Redocly/redoc/commit/bf960612a47bfe10ff205b9d78f3040515a5467d))
* more cases for react18 and cli integration ([#2416](https://github.com/Redocly/redoc/issues/2416)) ([26674e7](https://github.com/Redocly/redoc/commit/26674e70c66b686d0f0baa569b186292c41e5726))
## [2.1.2](https://github.com/Redocly/redoc/compare/v2.1.1...v2.1.2) (2023-09-11)
### Bug Fixes
* react18 cli integration ([#2404](https://github.com/Redocly/redoc/issues/2404)) ([76edc15](https://github.com/Redocly/redoc/commit/76edc159399150778b384be87ee958a93e5c491c))
* style RefreshToken URL as <code> in the authorization section ([1d61001](https://github.com/Redocly/redoc/commit/1d6100111a0f3b609dadbd706354ce6125947df2))
## [2.1.1](https://github.com/Redocly/redoc/compare/v2.1.0...v2.1.1) (2023-08-17)
### Bug Fixes
* hotfix, crash after 2.1 release ([0ab3428](https://github.com/Redocly/redoc/commit/0ab3428664f857ea07381686a2b4beb4c22b17c3))
# [2.1.0](https://github.com/Redocly/redoc/compare/v2.0.0...v2.1.0) (2023-08-10)
### Bug Fixes
* call onLoaded if specs are not found ([#2182](https://github.com/Redocly/redoc/issues/2182)) ([0753bbe](https://github.com/Redocly/redoc/commit/0753bbea4b1425bdb09225fca45effae8003dce8))
* default value for array query parameter ([#2186](https://github.com/Redocly/redoc/issues/2186)) ([3d410b6](https://github.com/Redocly/redoc/commit/3d410b6002c656efa780254c9c45c6249f90bce1))
* **demo:** Get CORS proxy to work in Chrome on Windows ([#2220](https://github.com/Redocly/redoc/issues/2220)) ([1597bae](https://github.com/Redocly/redoc/commit/1597bae4032b65a94211e80aad51867e5af1ceb3))
* error with immutable object spec ([#2179](https://github.com/Redocly/redoc/issues/2179)) ([53c4f36](https://github.com/Redocly/redoc/commit/53c4f36fad3e4453a72c1d136e37929de47cd35e))
* improve accessible label by using the property name ([#2224](https://github.com/Redocly/redoc/issues/2224)) ([12be1bc](https://github.com/Redocly/redoc/commit/12be1bc5ffa11f9092c2faacd69d787f4e899960))
* move role to list item to meet ARIA spec ([#2228](https://github.com/Redocly/redoc/issues/2228)) ([b8f7da6](https://github.com/Redocly/redoc/commit/b8f7da6b003ca12c1e2f0f4d42f3dd6d6f86ccac))
* remove GenericObject shim ([#2177](https://github.com/Redocly/redoc/issues/2177)) ([127ef26](https://github.com/Redocly/redoc/commit/127ef260b961e07c5f82a7494b51dd3f04294e87))
* renames 'FieldContstraints' to 'FieldConstraints' ([#2352](https://github.com/Redocly/redoc/issues/2352)) ([7e05202](https://github.com/Redocly/redoc/commit/7e052028d965624feb72d5f4b74fdb3c2d5df21f))
* schema oneOf title with const ([#2350](https://github.com/Redocly/redoc/issues/2350)) ([4386867](https://github.com/Redocly/redoc/commit/4386867d908eae2aed2b9fd86e9f5476aadce52b))
* **types/open-api:** import type ([#2213](https://github.com/Redocly/redoc/issues/2213)) ([33be51a](https://github.com/Redocly/redoc/commit/33be51a7a4068f44fd914314002c058a204ba0c2))
### Features
* add deprecation label to redoc-cli ([#2172](https://github.com/Redocly/redoc/issues/2172)) ([2ae7e08](https://github.com/Redocly/redoc/commit/2ae7e08af49321cea9bf2078f309b48bacf76ad6))
* add option to hide the example code when using the `SchemaDefinition` component ([#2157](https://github.com/Redocly/redoc/issues/2157)) ([168189b](https://github.com/Redocly/redoc/commit/168189b2fdcf3667422ce3940ace3eedd0bdf284))
* add support of react 18 ([#2369](https://github.com/Redocly/redoc/issues/2369)) ([054f604](https://github.com/Redocly/redoc/commit/054f604195629197aa8bd0fc46e91383ca5a05af))
* add x-tags ([#2355](https://github.com/Redocly/redoc/issues/2355)) ([0bb21c8](https://github.com/Redocly/redoc/commit/0bb21c812840999d2dd2d96da42124746440b035))
* enable keyboard navigation ([#2361](https://github.com/Redocly/redoc/issues/2361)) ([d21af58](https://github.com/Redocly/redoc/commit/d21af5841455901f0572ab475b7dc661acb86a71))
* indicate whether request body is required or optional ([#2175](https://github.com/Redocly/redoc/issues/2175)) ([d3ad792](https://github.com/Redocly/redoc/commit/d3ad7925cfbd90b59b502b5ef53228fcd34b8a1e))
# [2.0.0](https://github.com/Redocly/redoc/compare/v2.0.0-rc.77...v2.0.0) (2022-09-12)
@ -159,7 +218,7 @@
* implement configurable minimum characer length to init search ([#1402](https://github.com/Redocly/redoc/issues/1402)) ([0fa08fa](https://github.com/Redocly/redoc/commit/0fa08faab1c176a4bfc5a553e8e8f8b07aca659f))
* support OAS 3.1 unevaluatedProperties ([#1978](https://github.com/Redocly/redoc/issues/1978)) ([0755ac6](https://github.com/Redocly/redoc/commit/0755ac6f04514eb0c08f90afceeda7858206b435))
* publish dockerhub ([#1971](https://github.com/Redocly/redoc/issues/1971)) ([7e01a0](https://github.com/Redocly/redoc/commit/7e01a0cfe2ad8d06075bfc66ef3860edbef033f8))
* publish dockerhub ([#1971](https://github.com/Redocly/redoc/issues/1971)) ([7e01a0](https://github.com/Redocly/redoc/commit/7e01a0cfe2ad8d06075bfc66ef3860edbef033f8))
# [2.0.0-rc.67](https://github.com/Redocly/redoc/compare/v2.0.0-rc.66...v2.0.0-rc.67) (2022-04-28)
@ -498,7 +557,7 @@ closes: [#1506](https://github.com/Redocly/redoc/issues/1506), [#1478](https://g
### Bug Fixes
* invalid discriminator dropdown behaviour with enum ([be07197](https://github.com/Redocly/redoc/commit/be07197e6d1e85a3fd3e61189a36b288751c077d))
* invalid discriminator dropdown behavior with enum ([be07197](https://github.com/Redocly/redoc/commit/be07197e6d1e85a3fd3e61189a36b288751c077d))
@ -716,7 +775,7 @@ Same as rc.31 by mistake
### Bug Fixes
* empty servers behaviour per OAS spec ([ed1db0c](https://github.com/Redocly/redoc/commit/ed1db0c9027087ae0ae923e390e3e1d638a647ae)), closes [#1151](https://github.com/Redocly/redoc/issues/1151)
* empty servers behavior per OAS spec ([ed1db0c](https://github.com/Redocly/redoc/commit/ed1db0c9027087ae0ae923e390e3e1d638a647ae)), closes [#1151](https://github.com/Redocly/redoc/issues/1151)
* fix duplicated content in tags when using md headings ([a260c84](https://github.com/Redocly/redoc/commit/a260c8414c34a259a70a20ebcd20ecbb06c3d250)), closes [#1150](https://github.com/Redocly/redoc/issues/1150) [#1152](https://github.com/Redocly/redoc/issues/1152)
* use mobile menu background color value from theme ([#1144](https://github.com/Redocly/redoc/issues/1144)) ([41a9b3c](https://github.com/Redocly/redoc/commit/41a9b3c18228d236d182d3c15c9abc35ae72a0d5))
@ -1694,7 +1753,7 @@ Complete rewrite also means that this rewrite may introduce issues, but they sho
- no more GitHub pages-based CDN. Use [unpkg.com](https://unpkg.com/) to access ReDoc releases
### Known Regression (will be resolved before leaving alpha stage)
### Known Regression (resolved before leaving alpha stage)
- `lazyLoading` option not implemented yet
- Copying to clipboard of samples not implemented yet
- Search not implemented yet

341
README.md
View File

@ -8,17 +8,15 @@
# Generate interactive API documentation from OpenAPI definitions
[![Coverage Status](https://coveralls.io/repos/Redocly/redoc/badge.svg?branch=main&service=github)](https://coveralls.io/github/Redocly/redoc?branch=main) [![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/main/LICENSE)
[![npm](http://img.shields.io/npm/v/redoc.svg)](https://www.npmjs.com/package/redoc) [![License](https://img.shields.io/npm/l/redoc.svg)](https://github.com/Redocly/redoc/blob/main/LICENSE)
[![bundle size](http://img.badgesize.io/https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc) [![Docker Build Status](https://img.shields.io/docker/build/redocly/redoc.svg)](https://hub.docker.com/r/redocly/redoc/)
[![bundle size](http://img.badgesize.io/https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js?compression=gzip&max=300000)](https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js) [![npm](https://img.shields.io/npm/dm/redoc.svg)](https://www.npmjs.com/package/redoc) [![](https://data.jsdelivr.com/v1/package/npm/redoc/badge)](https://www.jsdelivr.com/package/npm/redoc)
</div>
**This is the README for the `2.x` version of Redoc (React-based).**
**The README for the `1.x` version is on the [v1.x](https://github.com/Redocly/redoc/tree/v1.x) branch.**
## About Redoc
Redoc is an open-source tool for generating documentation from OpenAPI (fka Swagger) definitions.
Redoc is an open source tool for generating documentation from OpenAPI (formerly Swagger) definitions.
By default Redoc offers a three-panel, responsive layout:
@ -30,102 +28,80 @@ By default Redoc offers a three-panel, responsive layout:
## Live demo
If you want to see how Redoc will render your OpenAPI definition,
If you want to see how Redoc renders your OpenAPI definition,
you can try it out online at https://redocly.github.io/redoc/.
A version of the Swagger Petstore API is displayed by default.
To test it with your own OpenAPI definition,
enter the URL for your definition and select **TRY IT**.
## Redoc vs. Reference vs. Portals
## Redoc features
Redoc is Redocly's community-edition product. Looking for something more?
Checkout the following feature comparison of Redocly's premium products versus Redoc:
| Features | Redoc | Reference | Portals |
|------------------------------|:---------:|:---------:|:-----------:|
| **Specs** | | | |
| Swagger 2.0 | √ | √ | √ |
| OpenAPI 3.0 | √ | √ | √ |
| OpenAPI 3.1 | √ (basic) | √ | √ |
| | | | |
| **Theming** | | | |
| Fonts/colors | √ | √ | √ |
| Extra theme options | | √ | √ |
| | | | |
| **Performance** | | | |
| Pagination | | √ | √ |
| Search (enhanced) | | √ | √ |
| Search (server-side) | | | √ |
| | | | |
| **Multiple APIs** | | | |
| Multiple versions | | √ | √ |
| Multiple APIs | | | √ |
| API catalog | | | √ |
| | | | |
| **Additional features** | | | |
| Try-it console | | √ | √ |
| Automated code samples | | √ | √ |
| Deep links | | √ | √ |
| More SEO control | | | √ |
| Contextual docs | | | √ |
| Landing pages | | | √ |
| React hooks for more control | | | √ |
| Personalization | | | √ |
| Analytics integrations | | | √ |
| Feedback | | | Coming Soon |
Refer to the Redocly's documentation for more information on these products:
- [Portals](https://redocly.com/docs/developer-portal/introduction/)
- [Reference](https://redocly.com/docs/api-reference-docs/getting-started/)
- [Redoc](https://redocly.com/docs/redoc/quickstart/intro/)
## Features
- Responsive three-panel design with menu/scrolling synchronization
- [Multiple deployment options](https://redocly.com/docs/redoc/quickstart/intro/)
- [Server-side rendering (SSR) ready](https://redocly.com/docs/redoc/quickstart/cli/#redoc-cli-commands)
- Support for OpenAPI 3.1, OpenAPI 3.0, and Swagger 2.0
- [Multiple deployment options](https://redocly.com/docs/redoc/)
- Interactive interface so your users can try the API immediately
- Ability to integrate your API introduction into the side menu
- High-level grouping in side menu with the [`x-tagGroups`](https://redocly.com/docs/api-reference-docs/specification-extensions/x-tag-groups/) specification extension
- [Simple integration with `create-react-app`](https://redocly.com/docs/redoc/quickstart/react/)
[Example repo](https://github.com/APIs-guru/create-react-app-redoc)
- [Command-line interface to bundle your docs into a **zero-dependency** HTML file](https://redocly.com/docs/cli/commands/build-docs/)
- Neat **interactive** documentation for nested objects <br>
![](docs/images/nested-demo.gif)
## Customization options
[<img alt="Customization services" src="http://i.imgur.com/c4sUF7M.png" height="60px">](https://redocly.com/#services)
- High-level grouping in side-menu with the [`x-tagGroups`](https://redocly.com/docs/api-reference-docs/specification-extensions/x-tag-groups/) specification extension
- Branding/customizations using the [`theme` option](https://redocly.com/docs/api-reference-docs/configuration/theming/)
## Support
- OpenAPI v3.0 support
- Basic OpenAPI v3.1 support
- Broad OpenAPI v2.0 feature support (yes, it supports even `discriminator`) <br>
![](docs/images/discriminator-demo.gif)
- Code samples support (via vendor extension) <br>
- Code samples support (with vendor extension) <br>
![](docs/images/code-samples-demo.gif)
## Releases
**Important:** all the 2.x releases are deployed to npm and can be used with Redocly-cdn:
- particular release, for example, `v2.0.0`: https://cdn.redoc.ly/redoc/v2.0.0/bundles/redoc.standalone.js
- `latest` release: https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js
## Usage
Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(deprecated)**:
- particular release, for example `v1.2.0`: https://rebilly.github.io/ReDoc/releases/v1.2.0/redoc.min.js
- `v1.x.x` release: https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js
- `latest` release: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js - it will point to latest 1.x.x release since 2.x releases are not hosted on this CDN but on unpkg.
Redoc is provided as a CLI tool (also distributed as a Docker image), HTML tag, and React component.
## Version Guidance
| Redoc Release | OpenAPI Specification |
|:--------------|:----------------------|
| 2.0.0-alpha.54| 3.1, 3.0.x, 2.0 |
| 2.0.0-alpha.x | 3.0, 2.0 |
| 1.19.x | 2.0 |
| 1.18.x | 2.0 |
| 1.17.x | 2.0 |
### Generate documentation from the CLI
If you have Node installed, quickly generate documentation using `npx`:
```
npx @redocly/cli build-docs openapi.yaml
```
The tool outputs by default to a file named `redoc-static.html` that you can open in your browser.
> [Redocly CLI](https://github.com/Redocly/redocly-cli/) does more than docs; check it out and add linting, bundling, and more to your API workflow.
### Add an HTML element to the page
Create an HTML page, or edit an existing one, and add the following within the body tags:
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
Open the HTML file in your browser, and your API documentation is shown on the page.
Add your own `spec-url` to the `<redoc>` tag; this attribute can also be a local file. The JavaScript library can also be installed locally using `npm` and served from your own server, see the [HTML deployment documentation](https://redocly.com/docs/redoc/deployment/html/) for more details.
### More usage options
Check out the [deployment documentation](./deploment/index/md) for more options, and detailed documentation for each.
## Redoc vs. Reference
Redoc is Redocly's community-edition product. Looking for something more?
We also offer [hosted API reference documentation](https://redocly.com/docs/api-registry/guides/api-registry-quickstart/)
with additional features including:
* Try-it console
* Automated code samples
* Pagination
* Extra theme options
### Documentation and resources
- [Reference docs](https://redocly.com/docs/api-reference-docs/getting-started/) - we take care of the hosting
- [Redoc](https://redocly.com/docs/redoc/) - detailed documentation for this open source project (also in the `docs/` folder)
- [Command-line interface to bundle your docs into a web-ready HTML file](https://redocly.com/docs/cli/commands/build-docs/)
- API linting, bundling, and much more with open source [Redocly CLI](https://redocly.com/docs/cli)
## Showcase
A sample of the organizations using Redocly tools in the wild:
- [Rebilly](https://api-reference.rebilly.com/)
- [Docker Engine](https://docs.docker.com/engine/api/v1.25/)
- [Zuora](https://www.zuora.com/developer/api-reference/)
@ -134,68 +110,17 @@ Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(d
- [APIs.guru](https://apis.guru/api-doc/)
- [BoxKnight](https://www.docs.boxknight.com/)
## Lint OpenAPI definitions
Redocly's CLI is an [open source command-line tool](https://github.com/Redocly/redocly-cli) that you can use to lint
your OpenAPI definition. Linting helps you to catch errors and inconsistencies in your
OpenAPI definition before publishing.
Refer to [Redocly configuration](https://redocly.com/docs/cli/configuration/) in the OpenAPI documentation for more information.
## Deployment
### TL;DR final code example
To render your OpenAPI definition using Redoc, use the following HTML code sample and
replace the `spec-url` attribute with the url or local file address to your definition.
```html
<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
</body>
</html>
```
For step-by-step instructions for how to get started using Redoc
to render your OpenAPI definition, refer to the
[**Redoc quickstart guide**](https://redocly.com/docs/redoc/quickstart/) and [**How to use the HTML element**](https://redocly.com/docs/redoc/deployment/html/).
## Redoc CLI
For more information on Redoc's command-line interface, refer to
[**Using the Redoc CLI**](https://redocly.com/docs/redoc/deployment/cli/).
_Pull requests to add your own API page to the list are welcome_
## Configuration
### Security Definition location
You can inject the Security Definitions widget into any place in your definition `description`.
For more information, refer to [Security definitions injection](docs/security-definitions-injection.md).
Redoc is highly configurable, see the [configuration documentation](docs/config.md) for details.
### OpenAPI specification extensions
Redoc uses the following [specification extensions](https://redocly.com/docs/api-reference-docs/spec-extensions/):
* [`x-logo`](docs/redoc-vendor-extensions.md#x-logo) - is used to specify API logo
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-traitTag`](docs/redoc-vendor-extensions.md#x-traitTag) - useful for tags that refer to non-navigation properties like Pagination, Rate-Limits, etc
* [`x-codeSamples`](docs/redoc-vendor-extensions.md#x-codeSamples) - specify operation code samples
* [`x-examples`](docs/redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](docs/redoc-vendor-extensions.md#x-nullable) - mark schema param as a nullable
@ -204,131 +129,23 @@ Redoc uses the following [specification extensions](https://redocly.com/docs/api
* [`x-servers`](docs/redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0)
* [`x-ignoredHeaderParameters`](docs/redoc-vendor-extensions.md#x-ignoredHeaderParameters) - ability to specify header parameter names to ignore
* [`x-additionalPropertiesName`](docs/redoc-vendor-extensions.md#x-additionalPropertiesName) - ability to supply a descriptive name for the additional property keys
* [`x-summary`](docs/redoc-vendor-extensions.md#x-summary) - For Response object, use as the response button text, with description rendered under the button
* [`x-extendedDiscriminator`](docs/redoc-vendor-extensions.md#x-extendedDiscriminator) - In Schemas, uses this to solve name-clash issues with the standard discriminator
* [`x-explicitMappingOnly`](docs/redoc-vendor-extensions.md#x-explicitMappingOnly) - In Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object
* [`x-summary`](docs/redoc-vendor-extensions.md#x-summary) - for Response object, use as the response button text, with description rendered under the button
* [`x-extendedDiscriminator`](docs/redoc-vendor-extensions.md#x-extendedDiscriminator) - in Schemas, uses this to solve name-clash issues with the standard discriminator
* [`x-explicitMappingOnly`](docs/redoc-vendor-extensions.md#x-explicitMappingOnly) - in Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object
### `<redoc>` options object
You can use all of the following options with the standalone version of the <redoc> tag by kebab-casing them. For example, `scrollYOffset` becomes `scroll-y-offset`, and `expandResponses` becomes `expand-responses`.
## Releases
* `disableSearch` - disable search indexing and search box.
* `minCharacterLengthToInitSearch` - set minimal characters length to init search, default `3`, minimal `1`.
* `expandDefaultServerVariables` - enable expanding default server variables, default `false`.
* `expandResponses` - specify which responses to expand by default by response codes. Values should be passed as comma-separated list without spaces e.g. `expandResponses="200,201"`. Special value `"all"` expands all responses by default. Be careful: this option can slow-down documentation rendering time.
* `generatedPayloadSamplesMaxDepth` - set the maximum render depth for JSON payload samples (responses and request body). The default value is `10`.
* `maxDisplayedEnumValues` - display only specified number of enum values. hide rest values under spoiler.
* `hideDownloadButton` - do not show "Download" spec button. **THIS DOESN'T MAKE YOUR SPEC PRIVATE**, it just hides the button.
* `downloadFileName` - set a custom file name for the downloaded API definition file.
* `downloadDefinitionUrl` - If the 'Download' button is visible in the API reference documentation (hideDownloadButton=false), the URL configured here will open when that button is selected. Provide it as an absolute URL with the full URI scheme.
* `hideHostname` - if set, the protocol and hostname is not shown in the operation definition.
* `hideLoading` - do not show loading animation. Useful for small docs.
* `hideFab` - do not show FAB in mobile view. Useful for implementing a custom floating action button.
* `hideSchemaPattern` - if set, the pattern is not shown in the schema.
* `hideSingleRequestSampleTab` - do not show the request sample tab for requests with only one sample.
* `showObjectSchemaExamples` - show object schema example in the properties, default `false`.
* `expandSingleSchemaField` - automatically expand single field in a schema
* `schemaExpansionLevel` - specifies whether to automatically expand schemas. Special value `"all"` expands all levels. The default value is `0`.
* `jsonSampleExpandLevel` - set the default expand level for JSON payload samples (responses and request body). Special value `"all"` expands all levels. The default value is `2`.
* `hideSchemaTitles` - do not display schema `title` next to to the type
* `simpleOneOfTypeLabel` - show only unique oneOf types in the label without titles
* `sortEnumValuesAlphabetically` - set to true, sorts all enum values in all schemas alphabetically
* `sortOperationsAlphabetically` - set to true, sorts operations in the navigation sidebar and in the middle panel alphabetically
* `sortTagsAlphabetically` - set to true, sorts tags in the navigation sidebar and in the middle panel alphabetically
* `lazyRendering` - _Not implemented yet_ ~~if set, enables lazy rendering mode in ReDoc. This mode is useful for APIs with big number of operations (e.g. > 50). In this mode ReDoc shows initial screen ASAP and then renders the rest operations asynchronously while showing progress bar on the top. Check out the [demo](\\redocly.github.io/redoc) for the example.~~
* `menuToggle` - if true clicking second time on expanded menu item will collapse it, default `true`.
* `nativeScrollbars` - use native scrollbar for sidemenu instead of perfect-scroll (scrolling performance optimization for big specs).
* `onlyRequiredInSamples` - shows only required fields in request samples.
* `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one.
* `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array.
* `scrollYOffset` - If set, specifies a vertical scroll-offset. This is often useful when there are fixed positioned elements at the top of the page, such as navbars, headers etc;
`scrollYOffset` can be specified in various ways:
* **number**: A fixed number of pixels to be used as offset.
* **selector**: selector of the element to be used for specifying the offset. The distance from the top of the page to the element's bottom will be used as offset.
* **function**: A getter function. Must return a number representing the offset (in pixels).
* `showExtensions` - show vendor extensions ("x-" fields). Extensions used by Redoc are ignored. Can be boolean or an array of `string` with names of extensions to display.
* `sortPropsAlphabetically` - sort properties alphabetically.
* `payloadSampleIdx` - if set, payload sample will be inserted at this index or last. Indexes start from 0.
* `theme` - Redoc theme. For details check [theme docs](#redoc-theme-object).
* `untrustedSpec` - if set, the spec is considered untrusted and all HTML/markdown is sanitized to prevent XSS. **Disabled by default** for performance reasons. **Enable this option if you work with untrusted user data!**
* `nonce` - if set, the provided value will be injected in every injected HTML element in the `nonce` attribute. Useful when using CSP, see https://webpack.js.org/guides/csp/.
* `sideNavStyle` - can be specified in various ways:
* **summary-only**: displays a summary in the sidebar navigation item. (**default**)
* **path-only**: displays a path in the sidebar navigation item.
* **id-only**: displays the operation id with a fallback to the path in the sidebar navigation item.
* `showWebhookVerb` - when set to `true`, shows the HTTP request method for webhooks in operations and in the sidebar.
**The README for the `1.x` version is on the [v1.x](https://github.com/Redocly/redoc/tree/v1.x) branch.**
All the 2.x releases are deployed to npm and can be used with Redocly-cdn:
- particular release, for example, `v2.0.0`: https://cdn.redoc.ly/redoc/v2.0.0/bundles/redoc.standalone.js
- `latest` release: https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js
Additionally, all the 1.x releases are hosted on our GitHub Pages-based CDN **(deprecated)**:
- particular release, for example `v1.2.0`: https://rebilly.github.io/ReDoc/releases/v1.2.0/redoc.min.js
- `v1.x.x` release: https://rebilly.github.io/ReDoc/releases/v1.x.x/redoc.min.js
- `latest` release: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js - points to latest 1.x.x release since 2.x releases are not hosted on this CDN but on unpkg.
### `<redoc>` theme object
* `spacing`
* `unit`: 5 # main spacing unit used in autocomputed theme values later
* `sectionHorizontal`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `sectionVertical`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `breakpoints` # breakpoints for switching three/two and mobile view layouts
* `small`: '50rem'
* `medium`: '85rem'
* `large`: '105rem'
* `colors`
* `tonalOffset`: 0.3 # default tonal offset used in computations
* `typography`
* `fontSize`: '14px'
* `lineHeight`: '1.5em'
* `fontWeightRegular`: '400'
* `fontWeightBold`: '600'
* `fontWeightLight`: '300'
* `fontFamily`: 'Roboto, sans-serif'
* `smoothing`: 'antialiased'
* `optimizeSpeed`: true
* `headings`
* `fontFamily`: 'Montserrat, sans-serif'
* `fontWeight`: '400'
* `lineHeight`: '1.6em'
* `code` # inline code styling
* `fontSize`: '13px'
* `fontFamily`: 'Courier, monospace'
* `lineHeight`: # COMPUTED: typography.lineHeight
* `fontWeight`: # COMPUTED: typography.fontWeightRegular
* `color`: '#e53935'
* `backgroundColor`: 'rgba(38, 50, 56, 0.05)'
* `wrap`: false # whether to break word for inline blocks (otherwise they can overflow)
* `links`
* `color`: # COMPUTED: colors.primary.main
* `visited`: # COMPUTED: typography.links.color
* `hover`: # COMPUTED: lighten(0.2 typography.links.color)
* `textDecoration`: 'auto'
* `hoverTextDecoration`: 'auto'
* `sidebar`
* `width`: '260px'
* `backgroundColor`: '#fafafa'
* `textColor`: '#333333'
* `activeTextColor`: # COMPUTED: theme.sidebar.textColor (if set by user) or theme.colors.primary.main
* `groupItems` # Group headings
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'uppercase'
* `level1Items` # Level 1 items like tags or section 1st level items
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'none'
* `arrow` # sidebar arrow
* `size`: '1.5em'
* `color`: # COMPUTED: theme.sidebar.textColor
* `logo`
* `maxHeight`: # COMPUTED: sidebar.width
* `maxWidth`: # COMPUTED: sidebar.width
* `gutter`: '2px' # logo image padding
* `rightPanel`
* `backgroundColor`: '#263238'
* `width`: '40%'
* `textColor`: '#ffffff'
* `servers`
* `overlay`
* `backgroundColor`: '#fafafa'
* `textColor`: '#263238'
* `url`
* `backgroundColor`: '#fff'
* `fab`
* `backgroundColor`: '#263238'
* `color`: '#ffffff'
-----------
## Development
see [CONTRIBUTING.md](.github/CONTRIBUTING.md)

20
cypress.config.ts Normal file
View File

@ -0,0 +1,20 @@
import { defineConfig } from 'cypress';
export default defineConfig({
fixturesFolder: false,
fileServerFolder: '.',
video: true,
projectId: 'z6eb6h',
viewportWidth: 1440,
viewportHeight: 720,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./e2e/plugins/index.js')(on, config);
},
excludeSpecPattern: '*.js.map',
specPattern: 'e2e/integration/**/*.{js,jsx,ts,tsx}',
supportFile: false,
},
});

View File

@ -1,12 +0,0 @@
{
"ignoreTestFiles": "*.js.map",
"integrationFolder": "e2e/integration",
"pluginsFile": "e2e/plugins/index.js",
"fixturesFolder": false,
"supportFile": false,
"fileServerFolder": ".",
"video": true,
"projectId": "z6eb6h",
"viewportWidth": 1440,
"viewportHeight": 720
}

View File

@ -6,8 +6,8 @@
import * as React from 'react';
import styled from '../src/styled-components';
const DropDownItem = styled.li<{ active?: boolean }>`
${(props: any) => (props.active ? 'background-color: #eee' : '')};
const DropDownItem = styled.li<{ $active?: boolean }>`
${(props: any) => (props.$active ? 'background-color: #eee' : '')};
padding: 13px 16px;
&:hover {
background-color: #eee;
@ -31,7 +31,7 @@ const DropDownList = styled.ul`
list-style: none;
margin: 4px 0 0 0;
padding: 5px 0;
font-family: Roboto,sans-serif;
font-family: Roboto, sans-serif;
overflow: hidden;
`;
@ -183,7 +183,7 @@ export default class ComboBox extends React.Component<ComboBoxProps, ComboBoxSta
renderOption = (option: { value: string; label: string }, idx: number) => {
return (
<DropDownItem
active={idx === this.state.activeItemIdx}
$active={idx === this.state.activeItemIdx}
key={option.value}
// tslint:disable-next-line
onMouseDown={() => {

View File

@ -17,7 +17,6 @@ const demos = [
},
{ value: 'https://api.apis.guru/v2/specs/slack.com/1.7.0/openapi.yaml', label: 'Slack' },
{ value: 'https://api.apis.guru/v2/specs/zoom.us/2.0.0/openapi.yaml', label: 'Zoom.us' },
{ value: 'https://docs.graphhopper.com/openapi.json', label: 'GraphHopper' },
];
class DemoApp extends React.Component<

View File

@ -1139,6 +1139,7 @@ components:
type: [string, integer, 'null']
minItems: 1
maxItems: 10
default: []
xml:
name: photoUrl
wrapped: true

View File

@ -1509,6 +1509,7 @@ components:
message:
type: string
Cat:
'x-tags': ['pet']
description: A representation of a cat
allOf:
- $ref: '#/components/schemas/Pet'
@ -1645,6 +1646,7 @@ components:
photoUrls:
description: The list of URL to a cute photos featuring pet
type: array
default: []
maxItems: 20
xml:
name: photoUrl
@ -1774,6 +1776,7 @@ components:
name:
type: string
description: hooray
default: []
description: Pet object that needs to be added to the store
required: true
UserArray:

View File

@ -780,6 +780,7 @@ definitions:
photoUrls:
description: The list of URL to a cute photos featuring pet
type: array
default: []
xml:
name: photoUrl
wrapped: true

View File

@ -76,7 +76,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
test: /\.(tsx?|[cm]?js)$/,
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2015',
tsconfigRaw: require('../tsconfig.json'),
},
@ -90,7 +89,6 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) =
{
loader: 'esbuild-loader',
options: {
loader: 'css',
minify: true,
},
},

266
docs/config.md Normal file
View File

@ -0,0 +1,266 @@
# Configure Redoc
Getting your documentation just right is important, and Redoc comes with many configuration options to help you succeed in that mission.
Each deployment type has documentation on how to configure options for that type of Redoc project. This page lists all the options you can use with Redoc.
**Versions: 2.x**
:::success Client-side configuration
Using Redoc as a standalone (HTML or React) tool, these options must be presented in [kebab case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case).
For example, `scrollYOffset` becomes `scroll-y-offset`, and `expandResponses` becomes `expand-responses`.
:::
## Functional settings
### disableSearch
Disables search indexing and hides the search box from the API documentation page.
### minCharacterLengthToInitSearch
Sets the minimum amount of characters that need to be typed into the search dialog to initiate the search.
_Default: 3_
### expandDefaultServerVariables
Enables or disables expanding default server variables.
### expandResponses
Controls which responses to expand by default. Specify one or more responses by providing their response codes as a comma-separated list without spaces, for example `expandResponses='200,201'`. Special value 'all' expands all responses by default. Be careful: this option can slow down documentation rendering time.
### expandSingleSchemaField
Automatically expands the single field in a schema.
### hideDownloadButton
Hides the 'Download' button for saving the API definition source file. **This setting does not make the API definition private**; it just hides the button.
### hideHostname
If set to `true`, the protocol and hostname are not shown in the operation definition.
### hideLoading
Hides the loading animation. Does not apply to CLI or Workflows-rendered docs.
### hideRequestPayloadSample
Hides request payload examples.
### hideOneOfDescription
If set to `true`, the description for `oneOf`/`anyOf` object is not shown in the schema.
### hideSchemaPattern
If set to `true`, the pattern is not shown in the schema.
### hideSchemaTitles
Hides the schema title next to to the type.
### hideSecuritySection
Hides the Security panel section.
### hideSingleRequestSampleTab
Hides the request sample tab for requests with only one sample.
### htmlTemplate
Sets the path to the optional HTML file used to modify the layout of the reference docs page.
### jsonSampleExpandLevel
Sets the default expand level for JSON payload samples (response and request body). The default value is 2, and the maximum supported value is '+Infinity'. It can also be configured as a string with the special value `all` that expands all levels.
_Default: 2_
### maxDisplayedEnumValues
Displays only the specified number of enum values. The remaining values are hidden in an expandable area. If not set, all values are displayed.
### menuToggle
If set to `true`, selecting an expanded item in the sidebar twice collapses it.
_Default: true_
### nativeScrollbars
If set to `true`, the sidebar uses the native scrollbar instead of perfect-scroll. This setting is a scrolling performance optimization for big API definitions.
### onlyRequiredInSamples
Shows only required fields in request samples.
### pathInMiddlePanel
Shows the path link and HTTP verb in the middle panel instead of the right panel.
### payloadSampleIdx
If set, the payload sample is inserted at the specified index. If there are `N` payload samples and the value configured here is bigger than `N`, the payload sample is inserted last. Indexes start from 0.
### requiredPropsFirst
Shows required properties in schemas first, ordered in the same order as in the required array.
### schemaExpansionLevel
Specifies whether to automatically expand schemas in Reference docs. Set it to `all` to expand all schemas regardless of their level, or set it to a number to expand schemas up to the specified level. For example, `schemaExpansionLevel: 3` expands schemas up to three levels deep. The default value is `0`, meaning no schemas are expanded automatically.
### scrollYOffset
Specifies a vertical scroll-offset.
This setting is useful when there are fixed positioned elements at the top of the page, such as navbars, headers, etc.
Note that you can specify the `scrollYOffset` value in any of the following ways:
- as a number - a fixed number of pixels to be used as the offset.
- as a CSS selector - the selector of the element to be used for specifying the offset. The distance from the top of the page to the element's bottom is used as the offset.
- a function (advanced) - a getter function. Must return a number representing the offset (in pixels).
### showExtensions
Shows specification extensions ('x-' fields). Extensions used by Redoc are ignored. The value can be boolean or an array of strings with names of extensions to display. When used as boolean and set to `true`, all specification extensions are shown.
### showObjectSchemaExamples
Shows object schema example in the properties; default `false`.
### showWebhookVerb
When set to `true`, shows the HTTP request method for webhooks in operations and in the sidebar.
### simpleOneOfTypeLabel
Shows only unique `oneOf` types in the label without titles.
### sortEnumValuesAlphabetically
When set to `true`, sorts all enum values in all schemas alphabetically.
### sortOperationsAlphabetically
When set to `true`, sorts operations in the navigation sidebar and in the middle panel alphabetically.
### sortPropsAlphabetically
When set to `true`, sorts properties in all schemas alphabetically.
### sortTagsAlphabetically
When set to true, sorts tags in the navigation sidebar and in the middle panel alphabetically. Note that only tags are sorted alphabetically in the middle panel, not the operations associated with each tag. To sort operations alphabetically as well, you must set the `sortOperationsAlphabetically` setting to `true`.
_Default: false_
### untrustedDefinition
If set to `true`, the API definition is considered untrusted and all HTML/Markdown is sanitized to prevent XSS.
## Theme settings
* `spacing`
* `unit`: 5 # main spacing unit used in autocomputed theme values later
* `sectionHorizontal`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `sectionVertical`: 40 # Horizontal section padding. COMPUTED: spacing.unit * 8
* `breakpoints` # breakpoints for switching three/two and mobile view layouts
* `small`: '50rem'
* `medium`: '85rem'
* `large`: '105rem'
* `colors`
* `tonalOffset`: 0.3 # default tonal offset used in computations
* `typography`
* `fontSize`: '14px'
* `lineHeight`: '1.5em'
* `fontWeightRegular`: '400'
* `fontWeightBold`: '600'
* `fontWeightLight`: '300'
* `fontFamily`: 'Roboto, sans-serif'
* `smoothing`: 'antialiased'
* `optimizeSpeed`: true
* `headings`
* `fontFamily`: 'Montserrat, sans-serif'
* `fontWeight`: '400'
* `lineHeight`: '1.6em'
* `code` # inline code styling
* `fontSize`: '13px'
* `fontFamily`: 'Courier, monospace'
* `lineHeight`: # COMPUTED: typography.lineHeight
* `fontWeight`: # COMPUTED: typography.fontWeightRegular
* `color`: '#e53935'
* `backgroundColor`: 'rgba(38, 50, 56, 0.05)'
* `wrap`: false # whether to break word for inline blocks (otherwise they can overflow)
* `links`
* `color`: # COMPUTED: colors.primary.main
* `visited`: # COMPUTED: typography.links.color
* `hover`: # COMPUTED: lighten(0.2 typography.links.color)
* `textDecoration`: 'auto'
* `hoverTextDecoration`: 'auto'
* `sidebar`
* `width`: '260px'
* `backgroundColor`: '#fafafa'
* `textColor`: '#333333'
* `activeTextColor`: # COMPUTED: theme.sidebar.textColor (if set by user) or theme.colors.primary.main
* `groupItems` # Group headings
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'uppercase'
* `level1Items` # Level 1 items like tags or section 1st level items
* `activeBackgroundColor`: # COMPUTED: theme.sidebar.backgroundColor
* `activeTextColor`: # COMPUTED: theme.sidebar.activeTextColor
* `textTransform`: 'none'
* `arrow` # sidebar arrow
* `size`: '1.5em'
* `color`: # COMPUTED: theme.sidebar.textColor
* `logo`
* `maxHeight`: # COMPUTED: sidebar.width
* `maxWidth`: # COMPUTED: sidebar.width
* `gutter`: '2px' # logo image padding
* `rightPanel`
* `backgroundColor`: '#263238'
* `width`: '40%'
* `textColor`: '#ffffff'
* `servers`
* `overlay`
* `backgroundColor`: '#fafafa'
* `textColor`: '#263238'
* `url`
* `backgroundColor`: '#fff'
* `fab`
* `backgroundColor`: '#263238'
* `color`: '#ffffff'
## Additional customization
### Security Definition location
You can inject the Security Definitions widget into any place in your definition `description`.
For more information, refer to [Security definitions injection](./security-definitions-injection.md).
### OpenAPI specification extensions
Redoc uses the following [specification extensions](https://redocly.com/docs/api-reference-docs/spec-extensions/):
* [`x-logo`](./redoc-vendor-extensions.md#x-logo) - is used to specify API logo
* [`x-traitTag`](./redoc-vendor-extensions.md#x-traittag) - useful for handling out common things like Pagination, Rate-Limits, etc
* [`x-codeSamples`](./redoc-vendor-extensions.md#x-codesamples) - specify operation code samples
* [`x-examples`](./redoc-vendor-extensions.md#x-examples) - specify JSON example for requests
* [`x-nullable`](./redoc-vendor-extensions.md#x-nullable) - mark schema param as a nullable
* [`x-displayName`](./redoc-vendor-extensions.md#x-displayname) - specify human-friendly names for the menu categories
* [`x-tagGroups`](./redoc-vendor-extensions.md#x-taggroups) - group tags by categories in the side menu
* [`x-servers`](./redoc-vendor-extensions.md#x-servers) - ability to specify different servers for API (backported from OpenAPI 3.0)
* [`x-ignoredHeaderParameters`](./redoc-vendor-extensions.md#x-ignoredheaderparameters) - ability to specify header parameter names to ignore
* [`x-additionalPropertiesName`](./redoc-vendor-extensions.md#x-additionalpropertiesname) - ability to supply a descriptive name for the additional property keys
* [`x-summary`](./redoc-vendor-extensions.md#x-summary) - For Response object, use as the response button text, with description rendered under the button
* [`x-extendedDiscriminator`](./redoc-vendor-extensions.md#x-extendeddiscriminator) - In Schemas, uses this to solve name-clash issues with the standard discriminator
* [`x-explicitMappingOnly`](./redoc-vendor-extensions.md#x-explicitmappingonly) - In Schemas, display a more descriptive property name in objects with additionalProperties when viewing the property list with an object

View File

@ -1,7 +1,6 @@
---
title: Use the Redoc CLI
redirectFrom:
- /docs/redoc/quickstart/cli/
seo:
title: Use the Redoc CLI
---
# How to use the Redocly CLI

View File

@ -1,7 +1,6 @@
---
title: Use the Redoc Docker image
redirectFrom:
- /docs/redoc/quickstart/docker/
seo:
title: Use the Redoc Docker image
---
# How to use the Redoc Docker image

View File

@ -1,123 +1,140 @@
---
title: Use the Redoc HTML element
redirectFrom:
- /docs/redoc/quickstart/html/
seo:
title: Use the Redoc HTML element
---
# How to use the Redoc HTML element
# Use Redoc in HTML
## Step 1 - Install Redoc
To render API documentation in an HTML page, start with the template below and
replace the `spec-url` value with the local file path or URL of your API
description.
You can install Redoc using one of the following package managers:
```html
<!DOCTYPE html>
<html>
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
- [npm](https://docs.npmjs.com/about-npm)
- [yarn](https://classic.yarnpkg.com/en/docs/getting-started)
:::attention Initialize your package manager
If you do not have a `package.json` file in your project directory,
you need to add one by initializing npm or yarn in your project. Use the command `npm init` for npm,
or `yarn init` for yarn. These initialization commands will lead you through the process
of creating a `package.json` file in your project.
For more information, see
[Creating a package.json file](https://docs.npmjs.com/creating-a-package-json-file)
in the npm documentation or [Yarn init](https://classic.yarnpkg.com/en/docs/cli/init/)
in the yarn documentation.
:::
### Install Redoc with yarn
After navigating to your project directory in your terminal, use the following command:
```bash
yarn add redoc
<!--
Redoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
</body>
</html>
```
### Install Redoc with npm
{% admonition type="success" name="URL or local file" %}
Set `spec-url` to a relative path if the file is local, e.g. `spec-url=my-api.yaml`. Use a full URL like the example above if it's hosted elsewhere.
{% /admonition %}
After navigating to your project directory in your terminal, use the following command:
Open the HTML file in your browser to see the HTML documentation rendering. You may want to read the next section and add some configuration to make your documentation your own.
```bash
npm i redoc
## Configure Redoc
Redoc is highly configurable, find a [full list of configuration options](../config.md) on the dedicated page.
To configure Redoc in HTML, add the property names to the HTML tag. Here's an example that makes all the required properties display first in the list:
```html
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json' required-props-first=true></redoc>
```
## Step 2 - Reference the Redoc script
Any of the individual properties can be added to the tag, as many as you need to get your API docs set up as you like them.
### Theme configuration
The `theme` configuration setting is more complex since it represents many nested options, you can supply these as a JSON string to the `theme` attribute. For example, to change the sidebar color you would use a tag like this:
```html
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'
required-props-first=true
theme='{
"sidebar": {
"backgroundColor": "lightblue"
}
}'
></redoc>
```
Check out the [list of options for theme configuration](../config.md#theme-settings) and build up the configuration that suits your API needs.
## Advanced options
### The Redoc object
As an alternative to the HTML tag, you can also initialise Redoc in a web page using the Redoc object and invoking it from JavaScript. This is useful for situations where you want to create dynamic content in a page, and also provides a simple way to attach the Redoc element to an existing container.
The Redoc object offers an `init` function:
```js
Redoc.init(specOrSpecUrl, options, element, callback)
```
- `specOrSpecUrl`: Either a JSON object with the OpenAPI definition or a file name/URL to the
definition in JSON or YAML format.
- `options`: See the [configuration reference](../config.md).
- `element`: DOM element Redoc is inserted into.
- `callback`(optional): Callback to be called after Redoc has been fully rendered.
It is also called on errors with `error` as the first argument.
Call `Redoc.init()` from the JavaScript on a web page to add the element to the named container. Below is an example of an HTML page with a `<div>` tag, and the JavaScript to add the Redoc object to it.
```html
<!DOCTYPE html>
<html>
<head />
<body>
<H1>Redoc in action</H1>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
<div id="redoc-container"></div>
<script>
Redoc.init('http://petstore.swagger.io/v2/swagger.json', {
"expandResponses": "200,400"
}, document.getElementById('redoc-container'))
</script>
</body>
</html>
```
This example also sets the configuration for `expandResponses` so all 200 and 400 status responses are shown unfolded and with their details visible when the page loads.
### Self-host dependencies
You can reference the Redoc script using either a link to the files hosted on a CDN
or the files located in your `node modules` folder.
or install to your `node-modules` folder. Using the CDN is the simplest option, but
if you need to host in a closed environment or have requirements around external
dependencies, it may be useful to self-host.
### CDN link
To reference the Redoc script with a CDN link:
The main example shows using the CDN:
```html
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
### Node modules link
If you would instead prefer to host the depdencies yourself, first install `redoc` using `npm`:
To reference the Redoc script with a node modules link:
```
npm install redoc
```
_(Yarn users can install the `redoc` package with `yarn`)_.
You can then reference the Redoc script with a node modules link:
```html
<script src="node_modules/redoc/bundles/redoc.standalone.js"> </script>
```
## Step 3 - Add the <redoc> element
You can add the <redoc> element to your HTML page and reference your OpenAPI
definition using the `spec-url` attribute, or you can initialize Redoc using
a globally exposed Redoc object.
### The `spec-url` attribute
To add the <redoc> element with the `spec-url` attribute:
```html
<redoc spec-url="url/to/your/spec"></redoc>
```
#### Examples
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<redoc spec-url="dist.json"></redoc>
```
### The Redoc object
To add the <redoc> element with a globally exposed Redoc object:
```js
Redoc.init(specOrSpecUrl, options, element, callback)
```
- `specOrSpecUrl`: Either a JSON object with the OpenAPI definition or a URL to the
definition in JSON or YAML format.
- `options`: See [features.openapi object](/docs/api-reference-docs/configuration/functionality.mdx) reference.
- `element`: DOM element Redoc will be inserted into.
- `callback`(optional): Callback to be called after Redoc has been fully rendered.
It is also called on errors with `error` as the first argument.
#### Examples
```html
<script>
Redoc.init('http://petstore.swagger.io/v2/swagger.json', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```
You can also use a local file (JSON or YAML) in your project, for instance:
```html
<script>
Redoc.init('dist.yaml', {
scrollYOffset: 50
}, document.getElementById('redoc-container'))
</script>
```

View File

@ -1,7 +1,6 @@
---
title: Redoc deployment guide
redirectFrom:
- /docs/redoc/quickstart/intro/
seo:
title: Redoc deployment guide
---
# Redoc deployment guide
@ -12,7 +11,7 @@ You should select the option that best fits your needs.
The following options are supported:
- **[Live demo](https://redocly.github.io/redoc/):**
The live demo offers a fast way to see how your OpenAPI will render with Redoc.
The live demo offers a fast way to see how your OpenAPI renders with Redoc.
A version of the Swagger Petstore API is displayed by default. To test it with your own OpenAPI definition, enter the URL for your
definition and select **TRY IT**.
- **[HTML element](./html.md):**
@ -28,7 +27,7 @@ The following options are supported:
### OpenAPI definition
You will need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions:
You need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions:
- OpenAPI 3.0
- [Rebilly Users OpenAPI Definition](https://raw.githubusercontent.com/Rebilly/api-definitions/main/openapi/users.yaml)
@ -37,10 +36,10 @@ You will need an OpenAPI definition. For testing purposes, you can use one of th
- [Thingful OpenAPI Definition](https://raw.githubusercontent.com/thingful/openapi-spec/master/spec/swagger.yaml)
- [Fitbit Plus OpenAPI Definition](https://raw.githubusercontent.com/TwineHealth/TwineDeveloperDocs/master/spec/swagger.yaml)
:::info OpenAPI specification
{% admonition type="info" name="OpenAPI specification" %}
For more information on the OpenAPI specification, refer to the [Learning OpenAPI 3](https://redocly.com/docs/resources/learning-openapi/)
section in the documentation.
:::
{% /admonition %}
### How to run Redoc locally
@ -105,7 +104,7 @@ npm install -g http-server
Then, `cd` into your project directory and run the following command:
```node
http-server
http - server;
```
The output after entering the command provides the local URL where the preview can be accessed.

View File

@ -1,7 +1,9 @@
---
title: Use the Redoc React component
redirectFrom:
- /docs/redoc/quickstart/react/
seo:
title: Use the Redoc React component
redirects:
'/docs/redoc/quickstart/react/':
to: '/docs/redoc/deployment/react/'
---
# How to use the Redoc React component
@ -71,7 +73,7 @@ is fully rendered or when an error occurs (with an error as the first argument).
```js
<RedocStandalone
specUrl="http://petstore.swagger.io/v2/swagger.json"
onLoaded={error => {
onLoaded={(error) => {
if (!error) {
console.log('Yay!');
}

97
docs/index.md Normal file
View File

@ -0,0 +1,97 @@
---
seo:
title: Redoc
---
# Redoc: Open source API documentation tool
Redoc is a clean and easy way to produce web-ready documentation from an OpenAPI description (Swagger is also still supported). With one command, create your documentation, and customize it to meet the needs of your users.
Redoc is based around a three panel layout, with clear sections for navigation, detailed documentation, and request/response examples.
## Headline features
* Modern layout with extensive customization options.
* Support for OpenAPI 3.1, 3.0 and older 2.0 and Swagger formats.
* Embed or build standalone HTML documentation.
* CLI tool for easy automation and local development.
## Demo
[Try the live demo](https://redocly.github.io/redoc/) and upload your own API specification there to try.
## Usage
Redoc is provided as a CLI tool (also distributed as a Docker image), HTML tag, and React component.
### Generate documentation from the CLI
If you have Node installed, quickly generate documentation using `npx`:
```
npx @redocly/cli build-docs openapi.yaml
```
The tool outputs by default to a file named `redoc-static.html` that you can open in your browser.
> [Redocly CLI](https://github.com/Redocly/redocly-cli/) does more than docs, check it out and add linting, bundling and more to your API workflow.
### Add an HTML element to the page
Create an HTML page, or edit an existing one, and add the following:
```html
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
```
Open the HTML file in your browser, and your API documentation is shown on the page.
Add your own `spec-url` to the `<redoc>` tag; this attribute can also be a local file. The JavaScript library can also be installed locally using `npm` and served from your own server, see the [HTML deployment documentation](https://redocly.com/docs/redoc/deployment/html/) for more details.
### More usage options
Check out the [deployment documentation](./deployment/intro.md) for more options, and detailed documentation for each.
## Configure Redoc
Redoc is highly configurable. Each deployment option accepts configuration in a way that's appropriate to that platform, but the options are the same for each. For example:
* Using [Redocly CLI](../cli/index.md), configuration goes in the `redocly.yaml` file, or can be supplied as command line parameters, such as `--theme.openapi.disableSearch`.
* Using HTML or React, configure by setting `option` in the tag.
Here's a sample `redocly.yaml` configuration file, showing a few common settings and tweaking some of the visual theme settings:
```yaml
theme:
openapi:
disableSearch: true
expandResponses: 200,202
jsonSampleExpandLevel: 1
theme:
sidebar:
backgroundColor: '#eae0cc'
textColor: '#3d005b'
colors:
primary:
main: '#660099'
typography:
fontSize: 14pt
headings:
fontWeight: bold
```
Redocly CLI detects a file named `redocly.yaml` in the same directory as you run the command and uses it. See the documentation with a command like this:
```
redocly preview-docs openapi.yaml
```
There are many, many more options available. Visit the [configuration reference](./config.md) for a complete list.
## Next steps
* If you are new to OpenAPI, try the [OpenAPI starter project](../cli/openapi-starter.md) for a great introduction.
* Ready to build documentation from an existing OpenAPI file? Go to the [Redoc quickstart](./quickstart.md) and get started.
* Learn more about the project by visiting [Redoc on GitHub](https://github.com/Redocly/redoc).

View File

@ -1,5 +1,6 @@
---
title: Redoc quickstart guide
seo:
title: Redoc quickstart guide
---
# Redoc quickstart guide
@ -43,12 +44,10 @@ replace the `spec-url` attribute with the URL or local file address to your defi
</html>
```
:::attention Redoc requires an HTTP server to run locally
{% admonition type="attention" name="Redoc requires an HTTP server to run locally" %}
Loading local OpenAPI definitions is impossible without running a web server because of issues with
[same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) and
other security reasons. Refer to [Running Redoc locally](./deployment/intro.md#how-to-run-redoc-locally) for more information.
:::
{% /admonition %}
For a more detailed explanation with step-by-step instructions and additional options for using Redoc, refer to the [Redoc deployment guide](./deployment/intro.md).

View File

@ -1,33 +1,56 @@
# Redoc vendor extensions
You can use the following [vendor extensions](https://swagger.io/specification/#specificationExtensions) with Redoc.
You can use the following [vendor extensions](https://redocly.com/docs/openapi-visual-reference/specification-extensions/) with Redoc.
- [Swagger Object](#swagger-object)
- [x-servers](#x-servers)
- [x-tagGroups](#x-taggroups)
- [Tag Group Object](#a-nametaggroupobjectatag-group-object)
- [x-ignoredHeaderParameters](#x-ignoredheaderparameters)
- [Info Object](#info-object)
- [x-logo](#x-logo)
- [Logo Object](#a-namelogoobjectalogo-object)
- [Tag Object](#tag-object)
- [x-traitTag](#x-traittag)
- [x-displayName](#x-displayname)
- [Operation Object](#operation-object-vendor-extensions)
- [x-codeSamples](#x-codesamples)
- [Code Sample Object](#a-namecodesampleobjectacode-sample-object)
- [Parameter Object](#parameter-object)
- [x-examples](#x-examples)
- [Response Object vendor extensions](#response-object-vendor-extensions)
- [x-summary](#x-summary)
- [Schema Object](#schema-object)
- [x-nullable](#x-nullable)
- [x-extendedDiscriminator](#x-extendeddiscriminator)
- [x-additionalPropertiesName](#x-additionalpropertiesname)
- [x-explicitMappingOnly](#x-explicitmappingonly)
- [Redoc vendor extensions](#redoc-vendor-extensions)
- [Swagger Object](#swagger-object)
- [x-servers](#x-servers)
- [x-tagGroups](#x-taggroups)
- [How to use with Redoc](#how-to-use-with-redoc)
- [Tag Group Object](#tag-group-object)
- [Fixed fields](#fixed-fields)
- [x-tagGroups example](#x-taggroups-example)
- [x-ignoredHeaderParameters](#x-ignoredheaderparameters)
- [How to use with Redoc](#how-to-use-with-redoc-1)
- [x-ignoredHeaderParameters example](#x-ignoredheaderparameters-example)
- [Info Object](#info-object)
- [x-logo](#x-logo)
- [How to use with Redoc](#how-to-use-with-redoc-2)
- [Logo Object](#logo-object)
- [Fixed fields](#fixed-fields-1)
- [x-logo example](#x-logo-example)
- [Tag Object](#tag-object)
- [x-traitTag](#x-traittag)
- [How to use with Redoc](#how-to-use-with-redoc-3)
- [x-traitTag example](#x-traittag-example)
- [x-displayName](#x-displayname)
- [Operation Object vendor extensions](#operation-object-vendor-extensions)
- [x-codeSamples](#x-codesamples)
- [How to use with Redoc](#how-to-use-with-redoc-4)
- [Code Sample Object](#code-sample-object)
- [Fixed fields](#fixed-fields-2)
- [Code Sample Object example](#code-sample-object-example)
- [Parameter Object](#parameter-object)
- [x-examples](#x-examples)
- [How to use with Redoc](#how-to-use-with-redoc-5)
- [Response Object vendor extensions](#response-object-vendor-extensions)
- [x-summary](#x-summary)
- [How to use with Redoc](#how-to-use-with-redoc-6)
- [Schema Object](#schema-object)
- [x-nullable](#x-nullable)
- [How to use with Redoc](#how-to-use-with-redoc-7)
- [x-extendedDiscriminator](#x-extendeddiscriminator)
- [How to use with Redoc](#how-to-use-with-redoc-8)
- [x-extendedDiscriminator example](#x-extendeddiscriminator-example)
- [x-additionalPropertiesName](#x-additionalpropertiesname)
- [How to use with Redoc](#how-to-use-with-redoc-9)
- [x-additionalPropertiesName example](#x-additionalpropertiesname-example)
- [x-explicitMappingOnly](#x-explicitmappingonly)
- [How to use with Redoc](#how-to-use-with-redoc-10)
- [x-explicitMappingOnly example](#x-explicitmappingonly-example)
### Swagger Object
Extends the OpenAPI root [OpenAPI Object](https://swagger.io/specification/#oasObject)
Extends the OpenAPI root [OpenAPI Object](https://redocly.com/docs/openapi-visual-reference/openapi/)
#### x-servers
Backported from OpenAPI 3.0 [`servers`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#serverObject). Currently doesn't support templates.
@ -36,13 +59,14 @@ Backported from OpenAPI 3.0 [`servers`](https://github.com/OAI/OpenAPI-Specifica
| Field Name | Type | Description |
| :------------- | :-----------: | :---------- |
| x-tagGroups | [ [Tag Group Object](#tagGroupObject) ] | A list of tag groups |
| x-tagGroups | [ [Tag Group Object](#tag-group-object) ] | A list of tag groups |
###### How to use with Redoc
`x-tagGroups` is used to group tags in the side menu.
Before you use `x-tagGroups`, make sure you **add all tags to a group**, since a tag that is not in a group, **will not be displayed** at all!
Before you use `x-tagGroups`, make sure you **add all tags to a group**, since a tag that is not in a group, **is not displayed** at all!
#### <a name="tagGroupObject"></a>Tag Group Object
<a name="tagGroupObject"></a>
#### Tag Group Object
Information about tags group
###### Fixed fields
| Field Name | Type | Description |
@ -89,7 +113,7 @@ x-tagGroups:
###### How to use with Redoc
Use `x-ignoredHeaderParameters` to specify header parameter names which are ignored by ReDoc.
Use `x-ignoredHeaderParameters` to specify header parameter names which are ignored by Redoc.
###### x-ignoredHeaderParameters example
```yaml
@ -104,17 +128,18 @@ x-ignoredHeaderParameters:
```
### Info Object
Extends the OpenAPI [Info Object](http://swagger.io/specification/#infoObject)
Extends the OpenAPI [Info Object](https://redocly.com/docs/openapi-visual-reference/info/)
#### x-logo
| Field Name | Type | Description |
| :------------- | :-----------: | :---------- |
| x-logo | [Logo Object](#logoObject) | The information about API logo |
| x-logo | [Logo Object](#logo-object) | The information about API logo |
###### How to use with Redoc
`x-logo` is used to specify API logo. The corresponding image is displayed just above the side-menu.
#### <a name="logoObject"></a>Logo Object
<a name="logoObject"></a>
#### Logo Object
The information about API logo
###### Fixed fields
@ -153,7 +178,7 @@ info:
```
### Tag Object
Extends the OpenAPI [Tag Object](http://swagger.io/specification/#tagObject)
Extends the OpenAPI [Tag Object](https://redocly.com/docs/openapi-visual-reference/tags/)
#### x-traitTag
| Field Name | Type | Description |
@ -187,24 +212,25 @@ x-traitTag: true
| x-displayName | string | Defines the text that is used for this tag in the menu and in section headings |
### Operation Object vendor extensions
Extends the OpenAPI [Operation Object](http://swagger.io/specification/#operationObject)
Extends the OpenAPI [Operation Object](https://redocly.com/docs/openapi-visual-reference/operation/)
#### x-codeSamples
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-codeSamples | [ [Code Sample Object](#codeSampleObject) ] | A list of code samples associated with operation |
| x-codeSamples | [ [Code Sample Object](#code-sample-object) ] | A list of code samples associated with operation |
###### How to use with Redoc
`x-codeSamples` are rendered on the right panel in Redoc.
#### <a name="codeSampleObject"></a>Code Sample Object
<a name="codeSampleObject"></a>
#### Code Sample Object
Operation code sample
###### Fixed fields
| Field Name | Type | Description |
| :---------- | :------: | :----------- |
| lang | string | Code sample language. Value should be one of the following [list](https://github.com/github/linguist/blob/master/lib/linguist/popular.yml) |
| label | string? | Code sample label e.g. `Node` or `Python2.7`, _optional_, `lang` will be used by default |
| label | string? | Code sample label, for example `Node` or `Python2.7`, _optional_, `lang` is used by default |
| source | string | Code sample source code |
@ -223,18 +249,18 @@ source: console.log('Hello World');
```
### Parameter Object
Extends the OpenAPI [Parameter Object](http://swagger.io/specification/#parameterObject)
Extends the OpenAPI [Parameter Object](https://redocly.com/docs/openapi-visual-reference/parameter/)
#### x-examples
| Field Name | Type | Description |
| :------------- | :------: | :---------- |
| x-examples | [Example Object](http://swagger.io/specification/#exampleObject) | Object that contains examples for the request. Applies when `in` is `body` and mime-type is `application/json` |
| x-examples | [Example Object](https://redocly.com/docs/openapi-visual-reference/example/) | Object that contains examples for the request. Applies when `in` is `body` and mime-type is `application/json` |
###### How to use with Redoc
`x-examples` are rendered in the JSON tab on the right panel in Redoc.
### Response Object vendor extensions
Extends the OpenAPI [Response Object](https://swagger.io/specification/#responseObject)
Extends the OpenAPI [Response Object](https://redocly.com/docs/openapi-visual-reference/response/).
#### x-summary
| Field Name | Type | Description |
@ -245,7 +271,7 @@ Extends the OpenAPI [Response Object](https://swagger.io/specification/#response
If specified, you can use `x-summary` as the response button text, with description rendered under the button.
### Schema Object
Extends the OpenAPI [Schema Object](http://swagger.io/specification/#schemaObject)
Extends the OpenAPI [Schema Object](https://redocly.com/docs/openapi-visual-reference/schemas/)
#### x-nullable
| Field Name | Type | Description |
@ -253,7 +279,7 @@ Extends the OpenAPI [Schema Object](http://swagger.io/specification/#schemaObjec
| x-nullable | boolean | marks schema as a nullable |
###### How to use with Redoc
Schemas marked as `x-nullable` are marked in Redoc with the label Nullable
Schemas marked as `x-nullable` are marked in Redoc with the label Nullable.
#### x-extendedDiscriminator
**ATTENTION**: This is a Redoc-specific vendor extension, and is not supported by other tools.
@ -264,7 +290,7 @@ Schemas marked as `x-nullable` are marked in Redoc with the label Nullable
###### How to use with Redoc
Redoc uses this vendor extension to solve name-clash issues with the standard `discriminator`.
Value of this field specifies the field which will be used as a extended discriminator.
Value of this field specifies the field which is used as an extended discriminator.
Redoc displays definition with selectpicker using which user can select value of the `x-extendedDiscriminator`-marked field.
Redoc displays the definition derived from the current (using `allOf`) and has `enum` with only one value which is the same as the selected value of the field specified as `x-extendedDiscriminator`.
@ -347,7 +373,7 @@ Extends the `discriminator` property of the schema object.
###### How to use with Redoc
Redoc uses this extension to filter the `discriminator` mappings shown in the selectpicker.
When set to `true`, the selectpicker will only list the the explicitly defined mappings. When `false`, the default behavior is kept, i.e. explicit and implicit mappings will be shown.
When set to `true`, the selectpicker lists only the explicitly defined mappings. When `false`, the default behavior is kept, in other words, explicit and implicit mappings are shown.
###### x-explicitMappingOnly example
@ -366,4 +392,4 @@ Pet:
bee: "#/components/schemas/HoneyBee"
```
Will show in the selectpicker only the items `cat` and `bee`, even though the `Dog` class inherits from the `Pet` class.
Shows in the selectpicker only the items `cat` and `bee`, even though the `Dog` class inherits from the `Pet` class.

View File

@ -1,19 +1,23 @@
# Injection security definitions
You can inject Security Definitions widget into any place of your specification `description`:
You can inject the Security Definitions widget anywhere in your specification `description`:
```markdown
...
# Authorization
Some description
<!-- ReDoc-Inject: <security-definitions> -->
<!-- Redoc-Inject: <security-definitions> -->
...
```
Inject instruction is wrapped into HTML comment so it is **visible only in ReDoc**. It won't be visible e.g. in SwaggerUI.
The inject instruction is wrapped in an HTML comment,
so it is **visible only in Redoc** and not visible, for instance, in the SwaggerUI.
# Default behavior
If injection tag is not found in the description it will be appended to the end
of description under `Authentication` header.
If `Authentication` header is already present in the description, Security Definitions won't be inserted and rendered at all.
If the injection tag is not found in the description, it is appended to the end
of description under the `Authentication` header.
If the `Authentication` header is already present in the description,
Security Definitions are not inserted or rendered.

View File

@ -1,80 +1,52 @@
describe('Menu', () => {
beforeEach(() => {
cy.visit('e2e/standalone.html');
});
describe('3.0 spec', () => {
beforeEach(() => {
cy.visit('e2e/standalone.html');
});
it('should have valid items count', () => {
cy.get('.menu-content').find('li').should('have.length', 40);
});
it('should have valid items count', () => {
cy.get('.menu-content').find('li').should('have.length', 34);
});
it('should update URL hash when clicking on menu items', () => {
cy.contains('[role=menuitem] > label.-depth1', 'pet').click({ force: true });
cy.get('li[data-item-id="schema/Cat"]')
.should('have.text', 'schemaCat')
.click({ force: true });
cy.location('hash').should('equal', '#schema/Cat');
});
it('should sync active menu items while scroll', () => {
cy.contains('h1', 'Introduction')
.scrollIntoView()
.get('[role=menuitem].active')
.should('have.text', 'Introduction');
it('should contains Cat schema in Pet using x-tags', () => {
cy.contains('[role=menuitem] > label.-depth1', 'pet').click({ force: true });
cy.location('hash').should('equal', '#tag/pet');
cy.contains('h2', 'Add a new pet to the store')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.children()
.last()
.should('have.text', 'Add a new pet to the store')
.should('be.visible');
});
cy.contains('[role=menuitem]', 'Find pet by ID').click({ force: true });
cy.location('hash').should('equal', '#tag/pet/operation/getPetById');
});
it('should sync active menu items while scroll back and scroll again', () => {
cy.contains('h2', 'Add a new pet to the store')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.children()
.last()
.should('have.text', 'Add a new pet to the store')
.should('be.visible');
it('should deactivate tag when other is activated', () => {
const petItem = () => cy.contains('[role=menuitem] > label.-depth1', 'pet');
cy.contains('h1', 'Swagger Petstore').scrollIntoView().wait(100);
petItem().click({ force: true }).should('have.class', 'active');
cy.contains('[role=menuitem] > label.-depth1', 'store').click({ force: true });
petItem().should('not.have.class', 'active');
});
cy.contains('h1', 'Introduction')
.scrollIntoView()
.wait(100)
.get('[role=menuitem].active')
.should('have.text', 'Introduction');
cy.url().should('include', '#section/Introduction');
});
it('should update URL hash when clicking on menu items', () => {
cy.contains('[role=menuitem].-depth1', 'pet').click({ force: true });
cy.location('hash').should('equal', '#tag/pet');
cy.contains('[role=menuitem]', 'Find pet by ID').click({ force: true });
cy.location('hash').should('equal', '#tag/pet/operation/getPetById');
});
it('should deactivate tag when other is activated', () => {
const petItem = () => cy.contains('[role=menuitem].-depth1', 'pet');
petItem().click({ force: true }).should('have.class', 'active');
cy.contains('[role=menuitem].-depth1', 'store').click({ force: true });
petItem().should('not.have.class', 'active');
});
it('should be able to open a response object to see more details', () => {
cy.contains('h2', 'Find pet by ID')
.scrollIntoView()
.wait(100)
.parent()
.find('div h3')
.should('have.text', 'Responses')
.parent()
.find('div:first button')
.click()
.should('have.attr', 'aria-expanded', 'true')
.parent()
.find('div h5')
.then($h5 => $h5[0].firstChild!.nodeValue!.trim())
.should('eq', 'Response Schema:');
it('should be able to open a response object to see more details', () => {
cy.contains('h2', 'Find pet by ID')
.scrollIntoView()
.wait(100)
.parent()
.find('div h3')
.should('have.text', 'Responses')
.parent()
.find('div:first button')
.click()
.should('have.attr', 'aria-expanded', 'true')
.parent()
.find('div h5')
.then($h5 => $h5[0].firstChild!.nodeValue!.trim())
.should('eq', 'Response Schema:');
});
});
it('should be able to open the operation details when the operation IDs have quotes', () => {
@ -85,7 +57,7 @@ describe('Menu', () => {
cy.url().should('include', 'deletePetBy%22Id');
});
it.only('should encode URL when the operation IDs have backslashes', () => {
it('should encode URL when the operation IDs have backslashes', () => {
cy.visit('e2e/standalone-3-1.html');
cy.get('label span[title="pet"]').click({ multiple: true, force: true });
cy.get('li').contains('OperationId with backslash').click({ multiple: true, force: true });

View File

@ -1,7 +1,7 @@
describe('Standalone bundle test', () => {
function baseCheck(name: string, url: string) {
describe(name, () => {
before(() => {
beforeEach(() => {
cy.visit(url);
});

View File

@ -12,9 +12,9 @@ const webpackOptions = {
exclude: [/node_modules/],
use: [
{
loader: 'ts-loader',
loader: 'esbuild-loader',
options: {
configFile: 'e2e/tsconfig.json',
tsconfigRaw: require('../tsconfig.json'),
},
},
],

11655
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "bandwidth-redoc",
"version": "0.1.0",
"version": "2.1.3",
"description": "Bandwidth ReDoc Fork",
"repository": {
"type": "git",
@ -61,9 +61,9 @@
"pre-commit": "pretty-quick --staged && npm run lint"
},
"devDependencies": {
"@cypress/webpack-preprocessor": "^5.12.0",
"@cypress/webpack-preprocessor": "^5.17.1",
"@hot-loader/react-dom": "^17.0.2",
"@size-limit/preset-app": "^7.0.4",
"@size-limit/preset-app": "^8.2.6",
"@types/chai": "^4.2.18",
"@types/dompurify": "^2.2.2",
"@types/enzyme": "^3.10.5",
@ -78,25 +78,24 @@
"@types/prop-types": "^15.7.3",
"@types/react": "^17.0.8",
"@types/react-dom": "^17.0.5",
"@types/react-tabs": "^2.3.2",
"@types/styled-components": "^5.1.1",
"@types/tapable": "^2.2.2",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.16.0",
"@types/webpack-env": "^1.18.0",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
"beautify-benchmark": "^0.2.4",
"conventional-changelog-cli": "^2.0.34",
"conventional-changelog-cli": "^3.0.0",
"copy-webpack-plugin": "^9.0.0",
"core-js": "^3.13.1",
"coveralls": "^3.1.0",
"coveralls": "^3.1.1",
"css-loader": "^5.2.6",
"cypress": "^7.4.0",
"cypress": "^13.1.0",
"enzyme": "^3.11.0",
"enzyme-to-json": "^3.6.2",
"esbuild-loader": "^2.18.0",
"esbuild-loader": "^3.0.1",
"eslint": "^7.27.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-react": "^7.25.1",
@ -118,29 +117,30 @@
"react-hot-loader": "^4.13.0",
"rimraf": "^3.0.2",
"shelljs": "^0.8.4",
"size-limit": "^7.0.4",
"size-limit": "^8.2.6",
"style-loader": "^3.3.1",
"styled-components": "^5.3.0",
"ts-jest": "^27.0.2",
"ts-loader": "^9.2.6",
"ts-node": "^10.0.0",
"ts-node": "^10.9.1",
"tslib": "^2.4.0",
"typescript": "~4.1.0",
"typescript": "^4.8.4",
"unfetch": "^4.2.0",
"webpack": "^5.50.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^4.6.0",
"url": "^0.11.1",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-node-externals": "^3.0.0",
"workerize-loader": "github:redocly/workerize-loader#webpack-5-dist"
},
"peerDependencies": {
"core-js": "^3.1.4",
"mobx": "^6.0.4",
"react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0",
"styled-components": "^4.1.1 || ^5.1.1"
"react": "^16.8.4 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0",
"styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5"
},
"dependencies": {
"@redocly/openapi-core": "^1.0.0-beta.104",
"@redocly/openapi-core": "^1.0.0-rc.2",
"classnames": "^2.3.1",
"decko": "^1.2.0",
"dompurify": "^2.2.8",
@ -156,10 +156,9 @@
"polished": "^4.1.3",
"prismjs": "^1.27.0",
"prop-types": "^15.7.2",
"react-tabs": "^3.2.2",
"react-tabs": "^4.3.0",
"slugify": "~1.4.7",
"stickyfill": "^1.1.1",
"style-loader": "^3.3.1",
"swagger2openapi": "^7.0.6",
"url-template": "^2.0.8"
},

View File

@ -70,7 +70,9 @@ export const TypeTitle = styled(FieldLabel)`
export const TypeFormat = TypeName;
export const RequiredLabel = styled(FieldLabel.withComponent('div'))`
export const RequiredLabel = styled(FieldLabel).attrs({
as: 'div',
})`
color: ${props => props.theme.schema.requireLabelColor};
font-size: ${props => props.theme.schema.labelsTextSize};
font-weight: normal;

View File

@ -1,14 +1,14 @@
import { SECTION_ATTR } from '../services/MenuStore';
import styled, { media } from '../styled-components';
export const MiddlePanel = styled.div<{ compact?: boolean }>`
export const MiddlePanel = styled.div<{ $compact?: boolean }>`
width: calc(100% - ${props => props.theme.rightPanel.width});
padding: 0 ${props => props.theme.spacing.sectionHorizontal}px;
${({ compact, theme }) =>
${({ $compact, theme }) =>
media.lessThan('medium', true)`
width: 100%;
padding: ${`${compact ? 0 : theme.spacing.sectionVertical}px ${
padding: ${`${$compact ? 0 : theme.spacing.sectionVertical}px ${
theme.spacing.sectionHorizontal
}px`};
`};
@ -16,7 +16,7 @@ export const MiddlePanel = styled.div<{ compact?: boolean }>`
export const Section = styled.div.attrs(props => ({
[SECTION_ATTR]: props.id,
}))<{ underlined?: boolean }>`
}))<{ $underlined?: boolean }>`
padding: ${props => props.theme.spacing.sectionVertical}px 0;
&:last-child {
@ -30,8 +30,8 @@ export const Section = styled.div.attrs(props => ({
${media.lessThan('medium', true)`
padding: 0;
`}
${(props: any) =>
(props.underlined &&
${({ $underlined }) =>
($underlined &&
`
position: relative;

View File

@ -32,7 +32,9 @@ export const SampleControlsWrap = styled.div`
}
`;
export const StyledPre = styled(PrismDiv.withComponent('pre'))`
export const StyledPre = styled(PrismDiv).attrs({
as: 'pre',
})`
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
overflow-x: auto;

View File

@ -15,7 +15,7 @@ export const OneOfLabel = styled.span`
}
`;
export const OneOfButton = styled.button<{ active: boolean; deprecated: boolean }>`
export const OneOfButton = styled.button<{ $active: boolean; $deprecated: boolean }>`
display: inline-block;
margin-right: 10px;
margin-bottom: 5px;
@ -29,10 +29,10 @@ export const OneOfButton = styled.button<{ active: boolean; deprecated: boolean
box-shadow: 0 0 0 1px ${props => props.theme.colors.primary.main};
}
${({ deprecated }) => (deprecated && deprecatedCss) || ''};
${({ $deprecated }) => ($deprecated && deprecatedCss) || ''};
${props => {
if (props.active) {
if (props.$active) {
return `
color: white;
background-color: ${props.theme.colors.primary.main};

View File

@ -24,7 +24,7 @@ export const CallbackTitle = (props: CallbackTitleProps) => {
<CallbackTitleWrapper className={className} onClick={onClick || undefined}>
<OperationBadgeStyled type={httpVerb}>{shortenHTTPVerb(httpVerb)}</OperationBadgeStyled>
<ShelfIcon size={'1.5em'} direction={opened ? 'down' : 'right'} float={'left'} />
<CallbackName deprecated={deprecated}>{name}</CallbackName>
<CallbackName $deprecated={deprecated}>{name}</CallbackName>
{deprecated ? <Badge type="warning"> {l('deprecated')} </Badge> : null}
</CallbackTitleWrapper>
);
@ -45,8 +45,8 @@ const CallbackTitleWrapper = styled.button`
}
`;
const CallbackName = styled.span<{ deprecated?: boolean }>`
text-decoration: ${props => (props.deprecated ? 'line-through' : 'none')};
const CallbackName = styled.span<{ $deprecated?: boolean }>`
text-decoration: ${props => (props.$deprecated ? 'line-through' : 'none')};
margin-right: 8px;
`;

View File

@ -51,7 +51,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
return (
<>
{content && (
<Section id={item.id} underlined={item.type === 'operation'}>
<Section id={item.id} $underlined={item.type === 'operation'}>
{content}
</Section>
)}
@ -61,7 +61,7 @@ export class ContentItem extends React.Component<ContentItemProps> {
}
}
const middlePanelWrap = component => <MiddlePanel compact={true}>{component}</MiddlePanel>;
const middlePanelWrap = component => <MiddlePanel $compact={true}>{component}</MiddlePanel>;
@observer
export class SectionItem extends React.Component<ContentItemProps> {
@ -72,7 +72,7 @@ export class SectionItem extends React.Component<ContentItemProps> {
return (
<>
<Row>
<MiddlePanel compact={false}>
<MiddlePanel $compact={false}>
<Header>
<ShareLink to={this.props.item.id} />
{name}

View File

@ -49,8 +49,8 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
<OptionsContext.Consumer>
{options => (
<OperationEndpointWrap className="endpoint">
<EndpointInfo onClick={this.toggle} expanded={expanded} inverted={inverted}>
<HttpVerb type={operation.httpVerb} compact={this.props.compact}>
<EndpointInfo onClick={this.toggle} $expanded={expanded} $inverted={inverted}>
<HttpVerb type={operation.httpVerb} $compact={this.props.compact}>
{operation.httpVerb}
</HttpVerb>
<ServerRelativeURL>{operation.path}</ServerRelativeURL>
@ -62,7 +62,7 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
style={{ marginRight: '-25px' }}
/>
</EndpointInfo>
<ServersOverlay expanded={expanded} aria-hidden={!expanded}>
<ServersOverlay $expanded={expanded} aria-hidden={!expanded}>
{operation.servers.map(server => {
const normalizedUrl = options.expandDefaultServerVariables
? expandDefaultServerVariables(server.url, server.variables)

View File

@ -14,61 +14,62 @@ export const ServerRelativeURL = styled.span`
text-overflow: ellipsis;
`;
export const EndpointInfo = styled.button<{ expanded?: boolean; inverted?: boolean }>`
export const EndpointInfo = styled.button<{ $expanded?: boolean; $inverted?: boolean }>`
outline: 0;
color: inherit;
width: 100%;
text-align: left;
cursor: pointer;
padding: 10px 30px 10px ${props => (props.inverted ? '10px' : '20px')};
border-radius: ${props => (props.inverted ? '0' : '4px 4px 0 0')};
padding: 10px 30px 10px ${props => (props.$inverted ? '10px' : '20px')};
border-radius: ${props => (props.$inverted ? '0' : '4px 4px 0 0')};
background-color: ${props =>
props.inverted ? 'transparent' : props.theme.codeBlock.backgroundColor};
props.$inverted ? 'transparent' : props.theme.codeBlock.backgroundColor};
display: flex;
white-space: nowrap;
align-items: center;
border: ${props => (props.inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.inverted ? '1px solid #ccc' : '0')};
border: ${props => (props.$inverted ? '0' : '1px solid transparent')};
border-bottom: ${props => (props.$inverted ? '1px solid #ccc' : '0')};
transition: border-color 0.25s ease;
${props =>
(props.expanded && !props.inverted && `border-color: ${props.theme.colors.border.dark};`) || ''}
(props.$expanded && !props.$inverted && `border-color: ${props.theme.colors.border.dark};`) ||
''}
.${ServerRelativeURL} {
color: ${props => (props.inverted ? props.theme.colors.text.primary : '#ffffff')};
color: ${props => (props.$inverted ? props.theme.colors.text.primary : '#ffffff')};
}
&:focus {
box-shadow: inset 0 2px 2px rgba(0, 0, 0, 0.45), 0 2px 0 rgba(128, 128, 128, 0.25);
}
`;
export const HttpVerb = styled.span.attrs((props: { type: string; compact?: boolean }) => ({
export const HttpVerb = styled.span.attrs((props: { type: string; $compact?: boolean }) => ({
className: `http-verb ${props.type}`,
}))<{ type: string; compact?: boolean }>`
font-size: ${props => (props.compact ? '0.8em' : '0.929em')};
line-height: ${props => (props.compact ? '18px' : '20px')};
}))<{ type: string; $compact?: boolean }>`
font-size: ${props => (props.$compact ? '0.8em' : '0.929em')};
line-height: ${props => (props.$compact ? '18px' : '20px')};
background-color: ${props => props.theme.colors.http[props.type] || '#999999'};
color: #ffffff;
padding: ${props => (props.compact ? '2px 8px' : '3px 10px')};
padding: ${props => (props.$compact ? '2px 8px' : '3px 10px')};
text-transform: uppercase;
font-family: ${props => props.theme.typography.headings.fontFamily};
margin: 0;
`;
export const ServersOverlay = styled.div<{ expanded: boolean }>`
export const ServersOverlay = styled.div<{ $expanded: boolean }>`
position: absolute;
width: 100%;
z-index: 100;
background: ${props => props.theme.rightPanel.servers.overlay.backgroundColor};
color: ${props => props.theme.rightPanel.servers.overlay.textColor};
box-sizing: border-box;
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.33);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.33);
overflow: hidden;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
transition: all 0.25s ease;
visibility: hidden;
${props => (props.expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')}
${props => (props.$expanded ? 'visibility: visible;' : 'transform: translateY(-50%) scaleY(0);')}
`;
export const ServerItem = styled.div`

View File

@ -4,9 +4,9 @@ import styled from '../../styled-components';
import { OpenAPIExternalDocumentation } from '../../types';
import { linksCss } from '../Markdown/styled.elements';
const LinkWrap = styled.div<{ compact?: boolean }>`
const LinkWrap = styled.div<{ $compact?: boolean }>`
${linksCss};
${({ compact }) => (!compact ? 'margin: 1em 0' : '')}
${({ $compact }) => (!$compact ? 'margin: 1em 0' : '')}
`;
@observer
@ -21,7 +21,7 @@ export class ExternalDocumentation extends React.Component<{
}
return (
<LinkWrap compact={this.props.compact}>
<LinkWrap $compact={this.props.compact}>
<a href={externalDocs.url}>{externalDocs.description || externalDocs.url}</a>
</LinkWrap>
);

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { TypeFormat, TypePrefix } from '../../common-elements/fields';
import { ConstraintsView } from './FieldContstraints';
import { ConstraintsView } from './FieldConstraints';
import { Pattern } from './Pattern';
import { SchemaModel } from '../../services';
import styled from '../../styled-components';
@ -10,15 +10,22 @@ export function ArrayItemDetails({ schema }: { schema: SchemaModel }) {
const { hideSchemaPattern } = React.useContext(OptionsContext);
if (
!schema ||
(schema.type === 'string' && !schema.constraints.length) ||
((!schema?.pattern || hideSchemaPattern) &&
!schema.items &&
!schema.displayFormat &&
!schema.constraints.length) // return null for cases where all constraints are empty
!schema.constraints?.length) // return null for cases where all constraints are empty
) {
return null;
}
if (schema.type === 'string' && schema.pattern) {
return (
<Wrapper>
[<Pattern schema={schema} />]
</Wrapper>
);
}
return (
<Wrapper>
[ items

View File

@ -15,7 +15,7 @@ import { EnumValues } from './EnumValues';
import { Extensions } from './Extensions';
import { FieldProps } from './Field';
import { Examples } from './Examples';
import { ConstraintsView } from './FieldContstraints';
import { ConstraintsView } from './FieldConstraints';
import { FieldDetail } from './FieldDetail';
import { Badge } from '../../common-elements/';
@ -51,10 +51,10 @@ export const FieldDetailsComponent = observer((props: FieldProps) => {
return null;
}, [field, showExamples]);
const defaultValue = isObject(schema.default)
? getSerializedValue(field, schema.default).replace(`${field.name}=`, '')
: schema.default;
const defaultValue =
isObject(schema.default) && field.in
? getSerializedValue(field, schema.default).replace(`${field.name}=`, '')
: schema.default;
return (
<div className="field-details">

View File

@ -4,26 +4,33 @@ import * as React from 'react';
import { OptionsConsumer } from '../OptionsProvider';
import { StylingMarkdownProps } from './Markdown';
import { StyledMarkdownBlock } from './styled.elements';
import styled from 'styled-components';
const StyledMarkdownSpan = StyledMarkdownBlock.withComponent('span');
const StyledMarkdownSpan = styled(props => <StyledMarkdownBlock {...props} />)`
display: inline;
`;
const sanitize = (untrustedSpec, html) => (untrustedSpec ? DOMPurify.sanitize(html) : html);
export function SanitizedMarkdownHTML(
props: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string },
) {
const Wrap = props.inline ? StyledMarkdownSpan : StyledMarkdownBlock;
export function SanitizedMarkdownHTML({
inline,
compact,
...rest
}: StylingMarkdownProps & { html: string; className?: string; 'data-role'?: string }) {
const Wrap = inline ? StyledMarkdownSpan : StyledMarkdownBlock;
return (
<OptionsConsumer>
{options => (
<Wrap
className={'redoc-markdown ' + (props.className || '')}
className={'redoc-markdown ' + (rest.className || '')}
dangerouslySetInnerHTML={{
__html: sanitize(options.untrustedSpec, props.html),
__html: sanitize(options.untrustedSpec, rest.html),
}}
data-role={props['data-role']}
{...props}
data-role={rest['data-role']}
{...rest}
$inline={inline}
$compact={compact}
/>
)}
</OptionsConsumer>

View File

@ -24,7 +24,7 @@ export const StyledMarkdownBlock = styled(
PrismDiv as StyledComponent<
'div',
ResolvedThemeInterface,
{ compact?: boolean; inline?: boolean }
{ $compact?: boolean; $inline?: boolean }
>,
)`
font-family: ${props => props.theme.typography.fontFamily};
@ -37,8 +37,8 @@ export const StyledMarkdownBlock = styled(
}
}
${({ compact }) =>
compact &&
${({ $compact }) =>
$compact &&
`
p:first-child {
margin-top: 0;
@ -48,8 +48,8 @@ export const StyledMarkdownBlock = styled(
}
`}
${({ inline }) =>
inline &&
${({ $inline }) =>
$inline &&
` p {
display: inline-block;
}`}
@ -87,7 +87,7 @@ export const StyledMarkdownBlock = styled(
padding: ${props => props.theme.spacing.unit * 4}px;
overflow-x: auto;
line-height: normal;
border-radius: 0px;
border-radius: 0;
border: 1px solid rgba(38, 50, 56, 0.1);
code {

View File

@ -10,7 +10,7 @@ import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
import { Schema } from '../Schema';
import { Markdown } from '../Markdown/Markdown';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
import { RequiredLabel } from '../../common-elements/fields';
import styled from '../../styled-components';

View File

@ -10,7 +10,7 @@ import { Schema } from '../Schema';
import { Extensions } from '../Fields/Extensions';
import { Markdown } from '../Markdown/Markdown';
import { ResponseHeaders } from './ResponseHeaders';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> {
render() {

View File

@ -41,7 +41,9 @@ export const ResponseDetailsWrap = styled.div`
padding: 10px;
`;
export const HeadersCaption = styled(UnderlinedHeader.withComponent('caption'))`
export const HeadersCaption = styled(UnderlinedHeader).attrs({
as: 'caption',
})`
text-align: left;
margin-top: 1em;
caption-side: top;

View File

@ -8,7 +8,7 @@ import {
} from '../../common-elements/schema';
import { Badge } from '../../common-elements/shelfs';
import { SchemaModel } from '../../services/models';
import { ConstraintsView } from '../Fields/FieldContstraints';
import { ConstraintsView } from '../Fields/FieldConstraints';
import { Schema, SchemaProps } from './Schema';
export interface OneOfButtonProps {
@ -23,8 +23,8 @@ export class OneOfButton extends React.Component<OneOfButtonProps> {
const { idx, schema, subSchema } = this.props;
return (
<StyledOneOfButton
deprecated={subSchema.deprecated}
active={idx === schema.activeOneOf}
$deprecated={subSchema.deprecated}
$active={idx === schema.activeOneOf}
onClick={this.activateOneOf}
>
{subSchema.title || subSchema.typePrefix + subSchema.displayType}

View File

@ -39,7 +39,7 @@ export function OAuthFlowComponent(props: OAuthFlowProps) {
{flow!.refreshUrl && (
<SecurityRow>
<strong> Refresh URL: </strong>
{flow!.refreshUrl}
<code>{flow!.refreshUrl}</code>
</SecurityRow>
)}
{!!scopesNames.length && (

View File

@ -18,9 +18,9 @@ export function SecurityHeader(props: SecurityRequirementProps) {
const grouping = security.schemes.length > 1;
if (security.schemes.length === 0)
return <SecurityRequirementOrWrap expanded={expanded}>None</SecurityRequirementOrWrap>;
return <SecurityRequirementOrWrap $expanded={expanded}>None</SecurityRequirementOrWrap>;
return (
<SecurityRequirementOrWrap expanded={expanded}>
<SecurityRequirementOrWrap $expanded={expanded}>
{grouping && '('}
{security.schemes.map(scheme => {
return (

View File

@ -37,12 +37,12 @@ export function SecurityRequirements(props: SecurityRequirementsProps) {
return (
<>
<Wrap expanded={expanded} className="operation-security">
<Wrap $expanded={expanded} className="operation-security">
<AuthHeaderColumn onClick={() => setExpanded(!expanded)}>
<AuthHeader>Authorizations:</AuthHeader>
<ShelfIcon size={'1.3em'} direction={expanded ? 'down' : 'right'} />
</AuthHeaderColumn>
<SecuritiesColumn expanded={expanded}>
<SecuritiesColumn $expanded={expanded}>
{securities.map((security, idx) => (
<SecurityHeader
key={idx}

View File

@ -55,11 +55,11 @@ export const SecurityRequirementAndWrap = styled.span`
${linksCss};
`;
export const SecurityRequirementOrWrap = styled.span<{ expanded?: boolean }>`
${p => !p.expanded && `white-space: nowrap;`}
export const SecurityRequirementOrWrap = styled.span<{ $expanded?: boolean }>`
${p => !p.$expanded && `white-space: nowrap;`}
&:after {
content: ' or ';
${p => p.expanded && `content: ' or \\a';`}
${p => p.$expanded && `content: ' or \\a';`}
white-space: pre;
}
@ -76,13 +76,13 @@ export const AuthHeaderColumn = styled.div`
cursor: pointer;
`;
export const SecuritiesColumn = styled.div<{ expanded?: boolean }>`
export const SecuritiesColumn = styled.div<{ $expanded?: boolean }>`
width: ${props => props.theme.schema.defaultDetailsWidth};
text-overflow: ellipsis;
border-radius: 4px;
overflow: hidden;
${p =>
p.expanded &&
p.$expanded &&
`background: ${p.theme.colors.gray['100']};
padding: 8px 9.6px;
margin: 20px 0;
@ -98,11 +98,11 @@ export const AuthHeader = styled(UnderlinedHeader)`
margin: 0;
`;
export const Wrap = styled.div<{ expanded?: boolean }>`
export const Wrap = styled.div<{ $expanded?: boolean }>`
width: 100%;
display: flex;
margin: 1em 0;
flex-direction: ${p => (p.expanded ? 'column' : 'row')};
flex-direction: ${p => (p.$expanded ? 'column' : 'row')};
${media.lessThan('small')`
flex-direction: column;
`}

View File

@ -32,7 +32,7 @@ export function SeeMore({ children, height }: SeeMoreProps): JSX.Element {
>
{children}
</Container>
<ButtonContainer dimmed={!showMore}>
<ButtonContainer $dimmed={!showMore}>
{showLink && (
<ButtonLinkStyled onClick={onClickMore}>
{showMore ? 'See less' : 'See more'}
@ -47,11 +47,11 @@ const Container = styled.div`
overflow-y: hidden;
`;
const ButtonContainer = styled.div<{ dimmed?: boolean }>`
const ButtonContainer = styled.div<{ $dimmed?: boolean }>`
text-align: center;
line-height: 1.5em;
${({ dimmed }) =>
dimmed &&
${({ $dimmed }) =>
$dimmed &&
`background-image: linear-gradient(to bottom, transparent,rgb(255 255 255));
position: relative;
top: -0.5em;

View File

@ -44,12 +44,19 @@ export class MenuItem extends React.Component<MenuItemProps> {
render() {
const { item, withoutChildren } = this.props;
return (
<MenuItemLi onClick={this.activate} depth={item.depth} data-item-id={item.id} role="menuitem">
<MenuItemLi
tabIndex={0}
onClick={this.activate}
depth={item.depth}
data-item-id={item.id}
role="menuitem"
>
{item.type === 'operation' ? (
<OperationMenuItemContent {...this.props} item={item as OperationModel} />
) : (
<MenuItemLabel depth={item.depth} active={item.active} type={item.type} ref={this.ref}>
<MenuItemTitle title={item.sidebarLabel}>
<MenuItemLabel $depth={item.depth} $active={item.active} $type={item.type} ref={this.ref}>
{item.type === 'schema' && <OperationBadge type="schema">schema</OperationBadge>}
<MenuItemTitle width="calc(100% - 38px)" title={item.sidebarLabel}>
{item.sidebarLabel}
{this.props.children}
</MenuItemTitle>
@ -88,7 +95,12 @@ export const OperationMenuItemContent = observer((props: OperationMenuItemConten
}, [props.item.active, ref]);
return (
<MenuItemLabel depth={item.depth} active={item.active} deprecated={item.deprecated} ref={ref}>
<MenuItemLabel
$depth={item.depth}
$active={item.active}
$deprecated={item.deprecated}
ref={ref}
>
{item.isWebhook ? (
<OperationBadge type="hook">
{showWebhookVerb ? item.httpVerb : l('webhook')}
@ -96,7 +108,7 @@ export const OperationMenuItemContent = observer((props: OperationMenuItemConten
) : (
<OperationBadge type={item.httpVerb}>{shortenHTTPVerb(item.httpVerb)}</OperationBadge>
)}
<MenuItemTitle width="calc(100% - 38px)">
<MenuItemTitle tabIndex={0} width="calc(100% - 38px)">
{item.sidebarLabel}
{props.children}
</MenuItemTitle>

View File

@ -25,7 +25,7 @@ export class MenuItems extends React.Component<MenuItemsProps> {
<MenuItemUl
className={className}
style={this.props.style}
expanded={expanded}
$expanded={expanded}
{...(root ? { role: 'menu' } : {})}
>
{items.map((item, idx) => (

View File

@ -26,43 +26,47 @@ export const OperationBadge = styled.span.attrs((props: { type: string }) => ({
margin-top: 2px;
&.get {
background-color: ${props => props.theme.colors.http.get};
background-color: ${({ theme }) => theme.colors.http.get};
}
&.post {
background-color: ${props => props.theme.colors.http.post};
background-color: ${({ theme }) => theme.colors.http.post};
}
&.put {
background-color: ${props => props.theme.colors.http.put};
background-color: ${({ theme }) => theme.colors.http.put};
}
&.options {
background-color: ${props => props.theme.colors.http.options};
background-color: ${({ theme }) => theme.colors.http.options};
}
&.patch {
background-color: ${props => props.theme.colors.http.patch};
background-color: ${({ theme }) => theme.colors.http.patch};
}
&.delete {
background-color: ${props => props.theme.colors.http.delete};
background-color: ${({ theme }) => theme.colors.http.delete};
}
&.basic {
background-color: ${props => props.theme.colors.http.basic};
background-color: ${({ theme }) => theme.colors.http.basic};
}
&.link {
background-color: ${props => props.theme.colors.http.link};
background-color: ${({ theme }) => theme.colors.http.link};
}
&.head {
background-color: ${props => props.theme.colors.http.head};
background-color: ${({ theme }) => theme.colors.http.head};
}
&.hook {
background-color: ${props => props.theme.colors.primary.main};
background-color: ${({ theme }) => theme.colors.primary.main};
}
&.schema {
background-color: ${({ theme }) => theme.colors.http.basic};
}
`;
@ -80,7 +84,7 @@ function menuItemActive(
}
}
export const MenuItemUl = styled.ul<{ expanded: boolean }>`
export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
margin: 0;
padding: 0;
@ -92,7 +96,7 @@ export const MenuItemUl = styled.ul<{ expanded: boolean }>`
font-size: 0.929em;
}
${props => (props.expanded ? '' : 'display: none;')};
${props => (props.$expanded ? '' : 'display: none;')};
`;
export const MenuItemLi = styled.li<{ depth: number }>`
@ -118,40 +122,40 @@ export const menuItemDepth = {
};
export interface MenuItemLabelType {
depth: number;
active: boolean;
deprecated?: boolean;
type?: string;
$depth: number;
$active: boolean;
$deprecated?: boolean;
$type?: string;
}
export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
className: classnames('-depth' + props.depth, {
active: props.active,
className: classnames('-depth' + props.$depth, {
active: props.$active,
}),
}))<MenuItemLabelType>`
cursor: pointer;
color: ${props =>
props.active
? menuItemActive(props.depth, props, 'activeTextColor')
props.$active
? menuItemActive(props.$depth, props, 'activeTextColor')
: props.theme.sidebar.textColor};
margin: 0;
padding: 12.5px ${props => props.theme.spacing.unit * 4}px;
${({ depth, type, theme }) =>
(type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
${({ $depth, $type, theme }) =>
($type === 'section' && $depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
display: flex;
justify-content: space-between;
font-family: ${props => props.theme.typography.headings.fontFamily};
${props => menuItemDepth[props.depth]};
${props => menuItemDepth[props.$depth]};
background-color: ${props =>
props.active
? menuItemActive(props.depth, props, 'activeBackgroundColor')
props.$active
? menuItemActive(props.$depth, props, 'activeBackgroundColor')
: props.theme.sidebar.backgroundColor};
${props => (props.deprecated && deprecatedCss) || ''};
${props => (props.$deprecated && deprecatedCss) || ''};
&:hover {
color: ${props => menuItemActive(props.depth, props, 'activeTextColor')};
background-color: ${props => menuItemActive(props.depth, props, 'activeBackgroundColor')};
color: ${props => menuItemActive(props.$depth, props, 'activeTextColor')};
background-color: ${props => menuItemActive(props.$depth, props, 'activeBackgroundColor')};
}
${ShelfIcon} {

View File

@ -25,7 +25,7 @@ export interface StickySidebarState {
const stickyfill = Stickyfill && Stickyfill();
const StyledStickySidebar = styled.div<{ open?: boolean }>`
const StyledStickySidebar = styled.div<{ $open?: boolean }>`
width: ${props => props.theme.sidebar.width};
background-color: ${props => props.theme.sidebar.backgroundColor};
overflow: hidden;
@ -45,7 +45,7 @@ const StyledStickySidebar = styled.div<{ open?: boolean }>`
z-index: 20;
width: 100%;
background: ${({ theme }) => theme.sidebar.backgroundColor};
display: ${props => (props.open ? 'flex' : 'none')};
display: ${props => (props.$open ? 'flex' : 'none')};
`};
@media print {
@ -130,7 +130,7 @@ export class StickyResponsiveSidebar extends React.Component<
return (
<>
<StyledStickySidebar
open={open}
$open={open}
className={this.props.className}
style={{
top,

View File

@ -0,0 +1,116 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import { FieldDetails } from '../Fields/FieldDetails';
import { SchemaModel } from '../../services/models/Schema';
import { withTheme } from '../testProviders';
jest.mock('../ExternalDocumentation/ExternalDocumentation', () => ({
ExternalDocumentation: () => {
return <div />;
},
}));
describe('FieldDetailsComponent', () => {
it('renders correctly', () => {
const mockFieldProps = {
showExamples: true,
field: {
schema: {
type: 'array',
default: [],
typePrefix: 'test type prefix',
displayType: 'array',
title: 'test title',
externalDocs: undefined,
constraints: [''],
} as SchemaModel,
example: 'example',
name: 'name',
expanded: false,
required: false,
kind: '',
deprecated: false,
collapse: jest.fn(),
toggle: jest.fn(),
explode: false,
expand: jest.fn(),
description: 'test description',
},
renderDiscriminatorSwitch: jest.fn(),
};
const wrapper = shallow(withTheme(<FieldDetails {...mockFieldProps} />));
expect(wrapper.render()).toMatchSnapshot();
});
it('renders correctly when default value is object in request body', () => {
const mockFieldProps = {
showExamples: true,
field: {
schema: {
type: 'object',
default: { properties: {} },
displayType: 'object',
title: 'test title',
externalDocs: undefined,
constraints: [''],
} as SchemaModel,
example: 'example',
name: 'name',
expanded: false,
required: false,
kind: '',
deprecated: false,
collapse: jest.fn(),
toggle: jest.fn(),
explode: false,
expand: jest.fn(),
description: 'test description',
in: undefined,
},
renderDiscriminatorSwitch: jest.fn(),
};
const wrapper = shallow(withTheme(<FieldDetails {...mockFieldProps} />));
expect(wrapper.render()).toMatchSnapshot();
});
it('renders correctly when field items have string type and pattern', () => {
const mockFieldProps = {
showExamples: true,
field: {
schema: {
type: 'array',
displayType: 'Array of strings',
title: 'test title',
externalDocs: undefined,
constraints: [''],
items: {
type: 'string',
pattern: '^see regex[0-9]$',
constraints: [''],
externalDocs: undefined,
},
} as any as SchemaModel,
example: 'example',
name: 'name',
expanded: false,
required: false,
kind: '',
deprecated: false,
collapse: jest.fn(),
toggle: jest.fn(),
explode: false,
expand: jest.fn(),
description: 'test description',
in: undefined,
},
renderDiscriminatorSwitch: jest.fn(),
};
const wrapper = shallow(withTheme(<FieldDetails {...mockFieldProps} />));
expect(wrapper.render()).toMatchSnapshot();
});
});

View File

@ -87,6 +87,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -376,6 +377,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -652,6 +654,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -990,6 +993,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -1291,6 +1295,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -1563,6 +1568,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -1860,6 +1866,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -2187,6 +2194,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -2476,6 +2484,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,
@ -2752,6 +2761,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
"hideDownloadButton": false,
"hideFab": false,
"hideHostname": false,
"hideRequestPayloadSample": false,
"hideSchemaPattern": false,
"hideSchemaTitles": false,
"hideSecuritySection": false,

View File

@ -0,0 +1,211 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`FieldDetailsComponent renders correctly 1`] = `
<div
class="field-details"
>
<div>
<span
class="sc-kpDqfm sc-dAlyuH cGRfjn gHomYR"
>
test type prefix
</span>
<span
class="sc-kpDqfm sc-jlZhew cGRfjn dYtiIA"
>
array
</span>
<span
class="sc-kpDqfm sc-cwHptR cGRfjn gyVIPr"
>
(test title)
</span>
<span
class="field-constraints"
>
<span
class="sc-kpDqfm sc-gFqAkR cGRfjn fYEICH"
>
</span>
</span>
</div>
<div>
<span
class="sc-kpDqfm cGRfjn"
>
Default:
</span>
<span
class="sc-kpDqfm sc-eldPxv cGRfjn ehWiAn field-example"
>
[]
</span>
</div>
<div>
<span
class="sc-kpDqfm cGRfjn"
>
Example:
</span>
<span
class="sc-kpDqfm sc-eldPxv cGRfjn ehWiAn field-example"
>
"example"
</span>
</div>
<div>
<div
class="sc-lcIPJg sc-hknOHE gBHqkN jFBMaE"
>
<p>
test description
</p>
</div>
</div>
</div>
`;
exports[`FieldDetailsComponent renders correctly when default value is object in request body 1`] = `
<div
class="field-details"
>
<div>
<span
class="sc-kpDqfm sc-dAlyuH cGRfjn gHomYR"
/>
<span
class="sc-kpDqfm sc-jlZhew cGRfjn dYtiIA"
>
object
</span>
<span
class="sc-kpDqfm sc-cwHptR cGRfjn gyVIPr"
>
(test title)
</span>
<span
class="field-constraints"
>
<span
class="sc-kpDqfm sc-gFqAkR cGRfjn fYEICH"
>
</span>
</span>
</div>
<div>
<span
class="sc-kpDqfm cGRfjn"
>
Default:
</span>
<span
class="sc-kpDqfm sc-eldPxv cGRfjn ehWiAn field-example"
>
{"properties":{}}
</span>
</div>
<div>
<span
class="sc-kpDqfm cGRfjn"
>
Example:
</span>
<span
class="sc-kpDqfm sc-eldPxv cGRfjn ehWiAn field-example"
>
"example"
</span>
</div>
<div>
<div
class="sc-lcIPJg sc-hknOHE gBHqkN jFBMaE"
>
<p>
test description
</p>
</div>
</div>
</div>
`;
exports[`FieldDetailsComponent renders correctly when field items have string type and pattern 1`] = `
<div
class="field-details"
>
<div>
<span
class="sc-kpDqfm sc-dAlyuH cGRfjn gHomYR"
/>
<span
class="sc-kpDqfm sc-jlZhew cGRfjn dYtiIA"
>
Array of strings
</span>
<span
class="sc-kpDqfm sc-cwHptR cGRfjn gyVIPr"
>
(test title)
</span>
<span
class="field-constraints"
>
<span
class="sc-kpDqfm sc-gFqAkR cGRfjn fYEICH"
>
</span>
</span>
<span
class="sc-kpDqfm sc-dAlyuH sc-dxcDKg cGRfjn gHomYR gXntsr"
>
[
<span
class="sc-kpDqfm sc-eDPEul cGRfjn erJHow field-pattern"
>
^see regex[0-9]$
</span>
]
</span>
</div>
<div>
<span
class="sc-kpDqfm cGRfjn"
>
Example:
</span>
<span
class="sc-kpDqfm sc-eldPxv cGRfjn ehWiAn field-example"
>
"example"
</span>
</div>
<div>
<div
class="sc-lcIPJg sc-hknOHE gBHqkN jFBMaE"
>
<p>
test description
</p>
</div>
</div>
</div>
`;

View File

@ -5,27 +5,27 @@ exports[`Components SchemaView OneOf deprecated should match snapshot 1`] = `
class="oneOf-schema"
>
<span
class="sc-kfYoZR juYXUf"
class="sc-fUnMCh hPwMmL"
>
One of
</span>
<div
class="sc-dlMDgC EoFth"
class="sc-feUZmu bTropM"
>
<button
class="sc-fKgJPI iEPbLk"
class="sc-hzhJZQ ilKqWS"
>
string
</button>
<button
class="sc-fKgJPI bpjiHN"
class="sc-hzhJZQ emRRrf"
>
integer
</button>
</div>
<div>
<span
class="sc-bqGGPW eSYQnm"
class="sc-jEACwC gWyYnj"
type="warning"
>
Deprecated
@ -37,10 +37,10 @@ exports[`Components SchemaView OneOf deprecated should match snapshot 1`] = `
>
<div>
<span
class="sc-laZMeE sc-iNiQyp jWaWWE jrLlAa"
class="sc-Nxspf sc-cfxfcM cXxAXt jrGEaR"
/>
<span
class="sc-laZMeE sc-jffHpj jWaWWE cThoNa"
class="sc-Nxspf sc-gFAWRd cXxAXt dYzdDr"
>
string
</span>
@ -48,7 +48,7 @@ exports[`Components SchemaView OneOf deprecated should match snapshot 1`] = `
<div>
<div
class="sc-iJCRrE sc-ciSkZP jCdxGr lhENGb"
class="sc-eeDRCY sc-eBMEME gTGgei fbXBig"
/>
</div>
</div>

View File

@ -1,23 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SecurityRequirement should render SecurityDefs 1`] = `
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">petstore_auth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
"<div id=\\"section/Authentication/petstore_auth\\" data-section-id=\\"section/Authentication/petstore_auth\\" class=\\"sc-dcJsrY bBkGhy\\"><div class=\\"sc-kAyceB hBQWIZ\\"><div class=\\"sc-fqkvVR oJKYx\\"><h2 class=\\"sc-jXbUNg fWnwAh\\">petstore_auth</h2><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>Get access to data while protecting your account credentials.
OAuth2 is also a safer and more secure way to give you access.</p>
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div class=\\"sc-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_OpenIdConnect\\" data-section-id=\\"section/Authentication/GitLab_OpenIdConnect\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">GitLab_OpenIdConnect</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div></div></div></div><div id=\\"section/Authentication/basicAuth\\" data-section-id=\\"section/Authentication/basicAuth\\" class=\\"sc-eCApnc jlMQbh\\"><div class=\\"sc-iCoGMd gLxhOh\\"><div class=\\"sc-hKFxyN juinod\\"><h2 class=\\"sc-pNWdM eftmgB\\">basicAuth</h2><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-eEVmNe lmbHgE\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div></div></div></div>"
</div><div class=\\"sc-ejfMa-d a-DjBE\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Security Scheme Type: </b><span>OAuth2</span></div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-dkmUuB hFwAIA\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div class=\\"sc-dkmUuB hFwAIA\\"><b> Scopes: </b></div><div class=\\"sc-iEXKAA blExNw container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru sc-fhzFiK hXtrri redoc-markdown\\"><p>modify pets in your account</p>
</div></li><li><code>read:pets</code> - <div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru sc-fhzFiK hXtrri redoc-markdown\\"><p>read your pets</p>
</div></li></ul></div><div class=\\"sc-EgOXT bNSpXO\\"></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_PersonalAccessToken\\" data-section-id=\\"section/Authentication/GitLab_PersonalAccessToken\\" class=\\"sc-dcJsrY bBkGhy\\"><div class=\\"sc-kAyceB hBQWIZ\\"><div class=\\"sc-fqkvVR oJKYx\\"><h2 class=\\"sc-jXbUNg fWnwAh\\">GitLab_PersonalAccessToken</h2><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-ejfMa-d a-DjBE\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Security Scheme Type: </b><span>API Key</span></div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div></div></div></div><div id=\\"section/Authentication/GitLab_OpenIdConnect\\" data-section-id=\\"section/Authentication/GitLab_OpenIdConnect\\" class=\\"sc-dcJsrY bBkGhy\\"><div class=\\"sc-kAyceB hBQWIZ\\"><div class=\\"sc-fqkvVR oJKYx\\"><h2 class=\\"sc-jXbUNg fWnwAh\\">GitLab_OpenIdConnect</h2><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-ejfMa-d a-DjBE\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Security Scheme Type: </b><span>OpenID Connect</span></div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div></div></div></div><div id=\\"section/Authentication/basicAuth\\" data-section-id=\\"section/Authentication/basicAuth\\" class=\\"sc-dcJsrY bBkGhy\\"><div class=\\"sc-kAyceB hBQWIZ\\"><div class=\\"sc-fqkvVR oJKYx\\"><h2 class=\\"sc-jXbUNg fWnwAh\\">basicAuth</h2><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"></div><div class=\\"sc-ejfMa-d a-DjBE\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Security Scheme Type: </b><span>HTTP</span></div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-dkmUuB hFwAIA\\"></div></div></div></div></div></div>"
`;
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-EZqKI eriJMk operation-security\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">Authorizations:</h5><svg class=\\"sc-dIsUp iPqByX\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-bQCEYZ cCwYjG\\"><span class=\\"sc-dWBRfb hoKBYz\\">(<span class=\\"sc-xGAEC bCFTJj\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC bCFTJj\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC bCFTJj\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb hoKBYz\\"><span class=\\"sc-xGAEC bCFTJj\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
exports[`SecurityRequirement should render authDefinition 1`] = `"<div class=\\"sc-bDumWk iWBBny operation-security\\"><div class=\\"sc-sLsrZ hgeUJn\\"><h5 class=\\"sc-dAlyuH sc-fifgRP jbQuod kWJur\\">Authorizations:</h5><svg class=\\"sc-cwHptR iZRiKW\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dBmzty eoFcYg\\"><span class=\\"sc-kbousE cpXQuZ\\">(<span class=\\"sc-gfoqjT kbvnry\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-gfoqjT kbvnry\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-gfoqjT kbvnry\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kbousE cpXQuZ\\"><span class=\\"sc-gfoqjT kbvnry\\">OAuth2: <i>petstore_auth</i></span></span></div></div>,"`;
exports[`SecurityRequirement should render authDefinition 2`] = `
"<div class=\\"sc-EZqKI hSmRqE operation-security\\"><div class=\\"sc-jHcXXw kurgNF\\"><h5 class=\\"sc-iqAclL sc-fXgAZx eONCmm xiVXt\\">Authorizations:</h5><svg class=\\"sc-dIsUp fVWtGJ\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-bQCEYZ gvMhNy\\"><span class=\\"sc-dWBRfb eLEzSd\\">(<span class=\\"sc-xGAEC bCFTJj\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-xGAEC bCFTJj\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-xGAEC bCFTJj\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-dWBRfb eLEzSd\\"><span class=\\"sc-xGAEC bCFTJj\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-kYPZxB beMTTe\\">write:pets</code><code class=\\"sc-kYPZxB beMTTe\\">read:pets</code>) </span></span></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OAuth2: petstore_auth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>Get access to data while protecting your account credentials.
"<div class=\\"sc-bDumWk gtsPcy operation-security\\"><div class=\\"sc-sLsrZ hgeUJn\\"><h5 class=\\"sc-dAlyuH sc-fifgRP jbQuod kWJur\\">Authorizations:</h5><svg class=\\"sc-cwHptR dSJqIk\\" version=\\"1.1\\" viewBox=\\"0 0 24 24\\" x=\\"0\\" xmlns=\\"http://www.w3.org/2000/svg\\" y=\\"0\\" aria-hidden=\\"true\\"><polygon points=\\"17.3 8.3 12 13.6 6.7 8.3 5.3 9.7 12 16.4 18.7 9.7 \\"></polygon></svg></div><div class=\\"sc-dBmzty llvZdI\\"><span class=\\"sc-kbousE dOwJQz\\">(<span class=\\"sc-gfoqjT kbvnry\\">API Key: <i>GitLab_PersonalAccessToken</i></span><span class=\\"sc-gfoqjT kbvnry\\">OpenID Connect: <i>GitLab_OpenIdConnect</i></span><span class=\\"sc-gfoqjT kbvnry\\">HTTP: <i>basicAuth</i></span>) </span><span class=\\"sc-kbousE dOwJQz\\"><span class=\\"sc-gfoqjT kbvnry\\">OAuth2: <i>petstore_auth</i> (<code class=\\"sc-eyvILC bzHwfc\\">write:pets</code><code class=\\"sc-eyvILC bzHwfc\\">read:pets</code>) </span></span></div></div><div class=\\"sc-ejfMa-d a-DjBE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OAuth2: petstore_auth</h5><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>Get access to data while protecting your account credentials.
OAuth2 is also a safer and more secure way to give you access.</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-jXcxbT gllWlr\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div><b>Required scopes: </b><code>write:pets</code> <code>read:pets</code> </div><div class=\\"sc-jXcxbT gllWlr\\"><b> Scopes: </b></div><div class=\\"sc-fmdNqN eKoRDV container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>modify pets in your account</p>
</span></li><li><code>read:pets</code> - <span class=\\"sc-carFqZ bmTzxo redoc-markdown\\"><p>read your pets</p>
</span></li></ul></div><div class=\\"sc-ljsmAU blhEdv\\"></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> API Key: GitLab_PersonalAccessToken</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OpenID Connect: GitLab_OpenIdConnect</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div><div class=\\"sc-eEVmNe lmbHgE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> HTTP: basicAuth</h5><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"></div><div class=\\"sc-iJCRrE sc-ciSkZP jCdxGr QGruV\\"><div class=\\"sc-jXcxbT gllWlr\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-jXcxbT gllWlr\\"></div></div></div>,"
</div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Flow type: </b><code>implicit </code></div><div class=\\"sc-dkmUuB hFwAIA\\"><strong> Authorization URL: </strong><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"http://petstore.swagger.io/api/oauth/dialog\\">http://petstore.swagger.io/api/oauth/dialog</a></code></div><div><b>Required scopes: </b><code>write:pets</code> <code>read:pets</code> </div><div class=\\"sc-dkmUuB hFwAIA\\"><b> Scopes: </b></div><div class=\\"sc-iEXKAA blExNw container\\" style=\\"height: 4em;\\"><ul><li><code>write:pets</code> - <div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru sc-fhzFiK hXtrri redoc-markdown\\"><p>modify pets in your account</p>
</div></li><li><code>read:pets</code> - <div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru sc-fhzFiK hXtrri redoc-markdown\\"><p>read your pets</p>
</div></li></ul></div><div class=\\"sc-EgOXT bNSpXO\\"></div></div></div><div class=\\"sc-ejfMa-d a-DjBE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> API Key: GitLab_PersonalAccessToken</h5><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>GitLab Personal Access Token description</p>
</div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Header parameter name: </b><code>PRIVATE-TOKEN</code></div></div></div><div class=\\"sc-ejfMa-d a-DjBE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> OpenID Connect: GitLab_OpenIdConnect</h5><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><p>GitLab OpenIdConnect description</p>
</div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>Connect URL: </b><code><a target=\\"_blank\\" rel=\\"noopener noreferrer\\" href=\\"https://gitlab.com/.well-known/openid-configuration\\">https://gitlab.com/.well-known/openid-configuration</a></code></div></div></div><div class=\\"sc-ejfMa-d a-DjBE security-details\\"><h5><svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 24 24\\" width=\\"11\\" height=\\"11\\"><path fill=\\"currentColor\\" d=\\"M18 10V6A6 6 0 0 0 6 6v4H3v14h18V10h-3zM8 6c0-2.206 1.794-4 4-4s4 1.794 4 4v4H8V6zm11 16H5V12h14v10z\\"></path></svg> HTTP: basicAuth</h5><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"></div><div class=\\"sc-eeDRCY sc-eBMEME gTGgei fMmru\\"><div class=\\"sc-dkmUuB hFwAIA\\"><b>HTTP Authorization Scheme: </b><code>basic</code></div><div class=\\"sc-dkmUuB hFwAIA\\"></div></div></div>,"
`;

View File

@ -1,4 +1,4 @@
import type { OpenAPISpec, OpenAPIPaths } from '../types';
import type { OpenAPISpec, OpenAPIPaths, OpenAPITag, OpenAPISchema } from '../types';
import { isOperationName, JsonPointer, alphabeticallyByProp } from '../utils';
import { MarkdownRenderer } from './MarkdownRenderer';
import { GroupModel, OperationModel } from './models';
@ -137,7 +137,14 @@ export class MenuBuilder {
continue;
}
const relatedSchemas = this.getTagRelatedSchema({
parser,
tag,
parent: item,
});
item.items = [
...relatedSchemas,
...MenuBuilder.addMarkdownItems(tag.description || '', item, item.depth + 1, options),
...this.getOperationsItems(parser, item, tag, item.depth + 1, options),
];
@ -248,4 +255,33 @@ export class MenuBuilder {
}
return tags;
}
static getTagRelatedSchema({
parser,
tag,
parent,
}: {
parser: OpenAPIParser;
tag: TagInfo;
parent: GroupModel;
}): GroupModel[] {
return Object.entries(parser.spec.components?.schemas || {})
.map(([schemaName, schema]) => {
const schemaTags = schema['x-tags'];
if (!schemaTags?.includes(tag.name)) return null;
const item = new GroupModel(
'schema',
{
name: schemaName,
'x-displayName': `${(schema as OpenAPISchema).title || schemaName}`,
description: `<SchemaDefinition showWriteOnly={true} schemaRef="#/components/schemas/${schemaName}" />`,
} as OpenAPITag,
parent,
);
item.depth = parent.depth + 1;
return item;
})
.filter(Boolean) as GroupModel[];
}
}

View File

@ -28,6 +28,7 @@ export interface RedocRawOptions {
showExtensions?: boolean | string | string[];
sideNavStyle?: SideNavStyleEnum;
hideSingleRequestSampleTab?: boolean | string;
hideRequestPayloadSample?: boolean;
menuToggle?: boolean | string;
jsonSampleExpandLevel?: number | string | 'all';
hideSchemaTitles?: boolean | string;
@ -231,6 +232,7 @@ export class RedocNormalizedOptions {
showExtensions: boolean | string[];
sideNavStyle: SideNavStyleEnum;
hideSingleRequestSampleTab: boolean;
hideRequestPayloadSample: boolean;
menuToggle: boolean;
jsonSampleExpandLevel: number;
enumSkipQuotes: boolean;
@ -302,6 +304,7 @@ export class RedocNormalizedOptions {
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
this.sideNavStyle = RedocNormalizedOptions.normalizeSideNavStyle(raw.sideNavStyle);
this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab);
this.hideRequestPayloadSample = argValueToBoolean(raw.hideRequestPayloadSample);
this.menuToggle = argValueToBoolean(raw.menuToggle, true);
this.jsonSampleExpandLevel = RedocNormalizedOptions.normalizeJsonSampleExpandLevel(
raw.jsonSampleExpandLevel,

View File

@ -562,5 +562,59 @@ describe('Models', () => {
`"testAttr: <object> (Refed description)"`,
);
});
test('should correct get title from in oneOf ->const', () => {
const spec = parseYaml(outdent`
openapi: 3.0.0
paths:
/test:
get:
operationId: test
responses:
'200':
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
response_code:
type: integer
description: A numeric response code
oneOf:
- const: 0
description: >
Description for const 0
- const: 1
description: >
Description for const 1
- const: 2
description: >
Description for const 2
`) as any;
parser = new OpenAPIParser(spec, undefined, opts);
const name = 'application/json';
const mediaType = new MediaTypeModel(
parser,
name,
true,
spec.paths['/test'].get.responses['200'].content[name],
opts,
);
expect(printSchema(mediaType?.schema as any)).toMatchInlineSnapshot(`
"data:
response_code: oneOf
0 -> <integer> (Description for const 0
)
1 -> <integer> (Description for const 1
)
2 -> <integer> (Description for const 2
)"
`);
});
});
});

View File

@ -202,6 +202,7 @@ export class OperationModel implements IMenuItem {
@memoize
get codeSamples() {
const { payloadSampleIdx, hideRequestPayloadSample } = this.options;
let samples: Array<OpenAPIXCodeSample | XPayloadSample> =
this.operationSpec['x-codeSamples'] || this.operationSpec['x-code-samples'] || [];
@ -211,8 +212,8 @@ export class OperationModel implements IMenuItem {
}
const requestBodyContent = this.requestBody && this.requestBody.content;
if (requestBodyContent && requestBodyContent.hasSample) {
const insertInx = Math.min(samples.length, this.options.payloadSampleIdx);
if (requestBodyContent && requestBodyContent.hasSample && !hideRequestPayloadSample) {
const insertInx = Math.min(samples.length, payloadSampleIdx);
samples = [
...samples.slice(0, insertInx),

View File

@ -243,8 +243,9 @@ export class SchemaModel {
const title =
isNamedDefinition(variant.$ref) && !merged.title
? JsonPointer.baseName(variant.$ref)
: `${merged.title || ''}${(merged.const && JSON.stringify(merged.const)) || ''}`;
: `${merged.title || ''}${
(typeof merged.const !== 'undefined' && JSON.stringify(merged.const)) || ''
}`;
const schema = new SchemaModel(
parser,
// merge base schema into each of oneOf's subschemas

View File

@ -83,7 +83,7 @@ export interface TagGroup {
tags: string[];
}
export type MenuItemGroupType = 'group' | 'tag' | 'section';
export type MenuItemGroupType = 'group' | 'tag' | 'section' | 'schema';
export type MenuItemType = MenuItemGroupType | 'operation';
export interface IMenuItem {

View File

@ -33,6 +33,7 @@ Object {
"schema": Object {
"properties": Object {
"name": Object {
"default": Array [],
"description": "hooray",
"type": "string",
},
@ -102,6 +103,9 @@ Object {
},
],
"description": "A representation of a cat",
"x-tags": Array [
"pet",
],
},
"Category": Object {
"properties": Object {
@ -286,6 +290,7 @@ Object {
"type": "string",
},
"photoUrls": Object {
"default": Array [],
"description": "The list of URL to a cute photos featuring pet",
"items": Object {
"format": "url",
@ -2793,6 +2798,7 @@ Object {
"type": "string",
},
"photoUrls": Object {
"default": Array [],
"description": "The list of URL to a cute photos featuring pet",
"else": Object {
"maxItems": 20,
@ -4683,6 +4689,7 @@ Object {
"type": "string",
},
"photoUrls": Object {
"default": Array [],
"description": "The list of URL to a cute photos featuring pet",
"items": Object {
"format": "url",

View File

@ -393,7 +393,7 @@ export function getSerializedValue(field: FieldModel, example: any) {
// decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138
return decodeURIComponent(serializeParameterValue(field, example));
} else {
return example;
return String(example);
}
}

View File

@ -56,6 +56,7 @@ export default (env: { standalone?: boolean; browser?: boolean } = {}) => ({
fs: path.resolve(__dirname, 'src/empty.js'),
os: path.resolve(__dirname, 'src/empty.js'),
tty: path.resolve(__dirname, 'src/empty.js'),
url: require.resolve('url/'),
},
},
performance: false,
@ -83,7 +84,6 @@ export default (env: { standalone?: boolean; browser?: boolean } = {}) => ({
test: /\.(tsx?|[cm]?js)$/,
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2015',
tsconfigRaw: require('./tsconfig.json'),
},
@ -97,7 +97,6 @@ export default (env: { standalone?: boolean; browser?: boolean } = {}) => ({
{
loader: 'esbuild-loader',
options: {
loader: 'css',
minify: true,
},
},