diff --git a/README.md b/README.md index 1bb94dbb..58cf29f6 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ 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 commmand-line interface, refer to +For more information on Redoc's command-line interface, refer to [**Using the Redoc CLI**](https://redocly.com/docs/redoc/deployment/cli/). diff --git a/src/components/Parameters/Parameters.tsx b/src/components/Parameters/Parameters.tsx index 3f4275df..34ba9574 100644 --- a/src/components/Parameters/Parameters.tsx +++ b/src/components/Parameters/Parameters.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel'; +import { DropdownOrLabel, DropdownOrLabelProps } from '../DropdownOrLabel/DropdownOrLabel'; import { ParametersGroup } from './ParametersGroup'; import { UnderlinedHeader } from '../../common-elements'; @@ -11,6 +11,8 @@ import { Schema } from '../Schema'; import { Markdown } from '../Markdown/Markdown'; import { ConstraintsView } from '../Fields/FieldContstraints'; +import { RequiredLabel } from '../../common-elements/fields'; +import styled from '../../styled-components'; function safePush(obj, prop, item) { if (!obj[prop]) { @@ -49,21 +51,37 @@ export class Parameters extends React.PureComponent { const bodyDescription = body && body.description; + const bodyRequired = body && body.required; + return ( <> {paramsPlaces.map(place => ( ))} - {bodyContent && } + {bodyContent && ( + + )} ); } } -function DropdownWithinHeader(props) { +function DropdownWithinHeader({ + bodyRequired, + ...props +}: DropdownOrLabelProps & { bodyRequired?: boolean }) { + const isRequired = typeof bodyRequired === 'boolean' && !!bodyRequired; + const isOptional = typeof bodyRequired === 'boolean' && !bodyRequired; + return ( Request Body schema: + {isRequired && required} + {isOptional && optional} ); } @@ -71,11 +89,15 @@ function DropdownWithinHeader(props) { export function BodyContent(props: { content: MediaContentModel; description?: string; + bodyRequired?: boolean; }): JSX.Element { - const { content, description } = props; + const { content, description, bodyRequired } = props; const { isRequestType } = content; return ( - + } + > {({ schema }) => { return ( <> @@ -95,3 +117,19 @@ export function BodyContent(props: { ); } + +const commonStyles = ` + text-transform: lowercase; + margin-left: 0; + line-height: 1.5em; +`; + +const RequiredBody = styled(RequiredLabel)` + ${commonStyles} +`; + +const OptionalBody = styled('div')` + ${commonStyles} + color: ${({ theme }) => theme.colors.text.secondary}; + font-size: ${props => props.theme.schema.labelsTextSize}; +`; diff --git a/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap b/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap index 506b6dd9..34ae4fc2 100644 --- a/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap @@ -3,21 +3,21 @@ exports[`SecurityRequirement should render SecurityDefs 1`] = ` "

petstore_auth

Get access to data while protecting your account credentials. OAuth2 is also a safer and more secure way to give you access.

-
Security Scheme Type: OAuth2
Flow type: implicit
Scopes:
  • write:pets -

    modify pets in your account

    +
Security Scheme Type: OAuth2
Flow type: implicit
Scopes:
  • write:pets -

    modify pets in your account

  • read:pets -

    read your pets

    -

GitLab_PersonalAccessToken

GitLab Personal Access Token description

-
Security Scheme Type: API Key
Header parameter name: PRIVATE-TOKEN

GitLab_OpenIdConnect

GitLab OpenIdConnect description

-
Security Scheme Type: OpenID Connect

basicAuth

Security Scheme Type: HTTP
HTTP Authorization Scheme: basic
" +

GitLab_PersonalAccessToken

GitLab Personal Access Token description

+
Security Scheme Type: API Key
Header parameter name: PRIVATE-TOKEN

GitLab_OpenIdConnect

GitLab OpenIdConnect description

+
Security Scheme Type: OpenID Connect

basicAuth

Security Scheme Type: HTTP
HTTP Authorization Scheme: basic
" `; -exports[`SecurityRequirement should render authDefinition 1`] = `"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth
,"`; +exports[`SecurityRequirement should render authDefinition 1`] = `"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth
,"`; exports[`SecurityRequirement should render authDefinition 2`] = ` -"
Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth (write:petsread:pets)
OAuth2: petstore_auth

Get access to data while protecting your account credentials. +"

Authorizations:
(API Key: GitLab_PersonalAccessTokenOpenID Connect: GitLab_OpenIdConnectHTTP: basicAuth) OAuth2: petstore_auth (write:petsread:pets)
OAuth2: petstore_auth

Get access to data while protecting your account credentials. OAuth2 is also a safer and more secure way to give you access.

-
Flow type: implicit
Required scopes: write:pets read:pets
Scopes:
  • write:pets -

    modify pets in your account

    +
Flow type: implicit
Required scopes: write:pets read:pets
Scopes:
  • write:pets -

    modify pets in your account

  • read:pets -

    read your pets

    -
API Key: GitLab_PersonalAccessToken

GitLab Personal Access Token description

-
Header parameter name: PRIVATE-TOKEN
OpenID Connect: GitLab_OpenIdConnect

GitLab OpenIdConnect description

-
HTTP: basicAuth
HTTP Authorization Scheme: basic
," +
API Key: GitLab_PersonalAccessToken

GitLab Personal Access Token description

+
Header parameter name: PRIVATE-TOKEN
OpenID Connect: GitLab_OpenIdConnect

GitLab OpenIdConnect description

+
HTTP: basicAuth
HTTP Authorization Scheme: basic
," `; diff --git a/src/services/__tests__/models/RequestBody.test.ts b/src/services/__tests__/models/RequestBody.test.ts index e8720c9b..a77725d4 100644 --- a/src/services/__tests__/models/RequestBody.test.ts +++ b/src/services/__tests__/models/RequestBody.test.ts @@ -23,6 +23,14 @@ describe('Models', () => { const consoleError = jest.spyOn(global.console, 'error'); const req = new RequestBodyModel(props); expect(consoleError).not.toHaveBeenCalled(); + expect(req).toEqual({ description: '', required: undefined }); + }); + + test('should work with set required', () => { + const consoleError = jest.spyOn(global.console, 'error'); + props.infoOrRef.required = false; + const req = new RequestBodyModel(props); + expect(consoleError).not.toHaveBeenCalled(); expect(req).toEqual({ description: '', required: false }); }); diff --git a/src/services/models/RequestBody.ts b/src/services/models/RequestBody.ts index ddb68d41..0b49cdc7 100644 --- a/src/services/models/RequestBody.ts +++ b/src/services/models/RequestBody.ts @@ -14,14 +14,14 @@ type RequestBodyProps = { export class RequestBodyModel { description: string; - required: boolean; + required?: boolean; content?: MediaContentModel; constructor({ parser, infoOrRef, options, isEvent }: RequestBodyProps) { const isRequest = !isEvent; const { resolved: info } = parser.deref(infoOrRef); this.description = info.description || ''; - this.required = !!info.required; + this.required = info.required; const mediaContent = getContentWithLegacyExamples(info); if (mediaContent !== undefined) {