diff --git a/docs/config.md b/docs/config.md index 9a668892e1..9a9475052c 100644 --- a/docs/config.md +++ b/docs/config.md @@ -6,7 +6,7 @@ Each deployment type has documentation on how to configure options for that type **Versions: 2.x** -{% admonition type="success" name="Client-side configuration" %} +{% admonition type="success" name="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`. @@ -66,6 +66,14 @@ If set to `true`, the pattern is not shown in the schema. Hides the schema title next to to the type. +### hideObjectTitle + +Hides the object title in the schema. + +### hideObjectDescription + +Hides the object description in the schema. + ### hideSecuritySection Hides the Security panel section. diff --git a/src/components/Fields/Field.tsx b/src/components/Fields/Field.tsx index d142c9a5c4..d4659dab27 100644 --- a/src/components/Fields/Field.tsx +++ b/src/components/Fields/Field.tsx @@ -104,7 +104,8 @@ export class Field extends React.Component { schema={field.schema} skipReadOnly={this.props.skipReadOnly} skipWriteOnly={this.props.skipWriteOnly} - showTitle={this.props.showTitle} + hideObjectTitle={this.props.hideObjectTitle} + hideObjectDescription={this.props.hideObjectDescription} level={this.props.level} /> diff --git a/src/components/Parameters/Parameters.tsx b/src/components/Parameters/Parameters.tsx index 5270d24097..d2b49506f2 100644 --- a/src/components/Parameters/Parameters.tsx +++ b/src/components/Parameters/Parameters.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { DropdownOrLabel, DropdownOrLabelProps } from '../DropdownOrLabel/DropdownOrLabel'; import { ParametersGroup } from './ParametersGroup'; +import { OptionsContext } from '../OptionsProvider'; import { UnderlinedHeader } from '../../common-elements'; @@ -29,6 +30,8 @@ export interface ParametersProps { const PARAM_PLACES = ['path', 'query', 'cookie', 'header']; export class Parameters extends React.PureComponent { + static contextType = OptionsContext; + orderParams(params: FieldModel[]): Record { const res = {}; params.forEach(param => { @@ -38,6 +41,7 @@ export class Parameters extends React.PureComponent { } render() { + const { hideObjectTitle, hideObjectDescription } = this.context; const { body, parameters = [] } = this.props; if (body === undefined && parameters === undefined) { return null; @@ -63,6 +67,8 @@ export class Parameters extends React.PureComponent { content={bodyContent} description={bodyDescription} bodyRequired={bodyRequired} + hideObjectTitle={hideObjectTitle} + hideObjectDescription={hideObjectDescription} /> )} @@ -90,8 +96,10 @@ export function BodyContent(props: { content: MediaContentModel; description?: string; bodyRequired?: boolean; + hideObjectTitle?: boolean; + hideObjectDescription?: boolean; }): JSX.Element { - const { content, description, bodyRequired } = props; + const { content, description, bodyRequired, hideObjectTitle, hideObjectDescription } = props; const { isRequestType } = content; return ( diff --git a/src/components/Responses/ResponseDetails.tsx b/src/components/Responses/ResponseDetails.tsx index 4800925910..adbe64241f 100644 --- a/src/components/Responses/ResponseDetails.tsx +++ b/src/components/Responses/ResponseDetails.tsx @@ -11,9 +11,13 @@ import { Extensions } from '../Fields/Extensions'; import { Markdown } from '../Markdown/Markdown'; import { ResponseHeaders } from './ResponseHeaders'; import { ConstraintsView } from '../Fields/FieldConstraints'; +import { OptionsContext } from '../OptionsProvider'; export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> { + static contextType = OptionsContext; + render() { + const { hideObjectTitle, hideObjectDescription } = this.context; const { description, extensions, headers, content } = this.props.response; return ( <> @@ -27,7 +31,13 @@ export class ResponseDetails extends React.PureComponent<{ response: ResponseMod {schema?.type === 'object' && ( )} - + ); }} diff --git a/src/components/Schema/ObjectSchema.tsx b/src/components/Schema/ObjectSchema.tsx index 145ea98d76..034e28f0b8 100644 --- a/src/components/Schema/ObjectSchema.tsx +++ b/src/components/Schema/ObjectSchema.tsx @@ -1,9 +1,13 @@ import { observer } from 'mobx-react'; import * as React from 'react'; +import styled from '../../styled-components'; +import { H3 } from '../../common-elements/headers'; +import { Markdown } from '../Markdown/Markdown'; + import { SchemaModel } from '../../services/models'; -import { PropertiesTable, PropertiesTableCaption } from '../../common-elements/fields-layout'; +import { PropertiesTable } from '../../common-elements/fields-layout'; import { Field } from '../Fields/Field'; import { DiscriminatorDropdown } from './DiscriminatorDropdown'; import { SchemaProps } from './Schema'; @@ -18,13 +22,26 @@ export interface ObjectSchemaProps extends SchemaProps { }; } +export const ObjectSchemaDetails = styled.div` + margin: 0 0 0.5em 0; +`; + +export const ObjectSchemaTitle = styled(H3)` + margin: 0.5em 0 0 0; +`; + +export const ObjectSchemaDescription = styled.div` + margin: 0.5em 0 0 0; +`; + export const ObjectSchema = observer( ({ - schema: { fields = [], title }, - showTitle, + schema: { fields = [], title, description }, discriminator, skipReadOnly, skipWriteOnly, + hideObjectTitle, + hideObjectDescription, level, }: ObjectSchemaProps) => { const { expandSingleSchemaField, showObjectSchemaExamples, schemaExpansionLevel } = @@ -48,37 +65,48 @@ export const ObjectSchema = observer( (expandSingleSchemaField && filteredFields.length === 1) || schemaExpansionLevel >= level!; return ( - - {showTitle && {title}} - - {mapWithLast(filteredFields, (field, isLast) => { - return ( - ( - - ) - : undefined - } - className={field.expanded ? 'expanded' : undefined} - showExamples={showObjectSchemaExamples} - skipReadOnly={skipReadOnly} - skipWriteOnly={skipWriteOnly} - showTitle={showTitle} - level={level} - /> - ); - })} - - +
+ + {!hideObjectTitle && {title}} + {!hideObjectDescription && ( + + + + )} + + + + + {mapWithLast(filteredFields, (field, isLast) => { + return ( + ( + + ) + : undefined + } + className={field.expanded ? 'expanded' : undefined} + showExamples={showObjectSchemaExamples} + skipReadOnly={skipReadOnly} + skipWriteOnly={skipWriteOnly} + hideObjectTitle={hideObjectTitle} + hideObjectDescription={hideObjectDescription} + level={level} + /> + ); + })} + + +
); }, ); diff --git a/src/components/Schema/Schema.tsx b/src/components/Schema/Schema.tsx index c0d38b1ea8..0bf72e051f 100644 --- a/src/components/Schema/Schema.tsx +++ b/src/components/Schema/Schema.tsx @@ -13,9 +13,10 @@ import { RecursiveSchema } from './RecursiveSchema'; import { isArray } from '../../utils/helpers'; export interface SchemaOptions { - showTitle?: boolean; skipReadOnly?: boolean; skipWriteOnly?: boolean; + hideObjectTitle?: boolean; + hideObjectDescription?: boolean; level?: number; } diff --git a/src/components/SchemaDefinition/SchemaDefinition.tsx b/src/components/SchemaDefinition/SchemaDefinition.tsx index b939891230..264c4d6170 100644 --- a/src/components/SchemaDefinition/SchemaDefinition.tsx +++ b/src/components/SchemaDefinition/SchemaDefinition.tsx @@ -14,6 +14,8 @@ export interface ObjectDescriptionProps { exampleRef?: string; showReadOnly?: boolean; showWriteOnly?: boolean; + showObjectTitle?: boolean; + showObjectDescription?: boolean; showExample?: boolean; parser: OpenAPIParser; options: RedocNormalizedOptions; @@ -54,7 +56,13 @@ export class SchemaDefinition extends React.PureComponent @@ -62,6 +70,8 @@ export class SchemaDefinition extends React.PureComponent diff --git a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap index 31e0327d9e..c3f91f952b 100644 --- a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap @@ -2865,143 +2865,156 @@ exports[`Components SchemaView discriminator should correctly render SchemaView `; exports[`Components SchemaView discriminator should correctly render discriminator dropdown 1`] = ` - - - + + + Dog + + + + + + + + >>", - "pattern": undefined, - "pointer": "#/components/schemas/Dog/properties/packSize", - "rawSchema": Object { - "default": undefined, - "type": "number", - }, - "readOnly": false, - "refsStack": Array [ - "#/components/schemas/Dog", - "#/components/schemas/Dog/properties/packSize", - ], - "schema": Object { + "expanded": undefined, + "explode": false, + "in": undefined, + "kind": "field", + "name": "packSize", + "required": false, + "schema": SchemaModel { + "activeOneOf": 0, + "const": "", + "constraints": Array [], + "contentEncoding": undefined, + "contentMediaType": undefined, "default": undefined, + "deprecated": false, + "description": "", + "displayFormat": undefined, + "displayType": "number", + "enum": Array [], + "example": undefined, + "examples": undefined, + "externalDocs": undefined, + "format": undefined, + "isCircular": false, + "isPrimitive": true, + "maxItems": undefined, + "minItems": undefined, + "options": "<<>>", + "pattern": undefined, + "pointer": "#/components/schemas/Dog/properties/packSize", + "rawSchema": Object { + "default": undefined, + "type": "number", + }, + "readOnly": false, + "refsStack": Array [ + "#/components/schemas/Dog", + "#/components/schemas/Dog/properties/packSize", + ], + "schema": Object { + "default": undefined, + "type": "number", + }, + "title": "", "type": "number", + "typePrefix": "", + "writeOnly": false, }, - "title": "", - "type": "number", - "typePrefix": "", - "writeOnly": false, - }, + } } - } - isLast={false} - key="packSize" - showExamples={false} - /> - + >>", - "pattern": undefined, - "pointer": "#/components/schemas/Dog/properties/type", - "rawSchema": Object { + "expanded": undefined, + "explode": false, + "in": undefined, + "kind": "field", + "name": "type", + "required": true, + "schema": SchemaModel { + "activeOneOf": 0, + "const": "", + "constraints": Array [], + "contentEncoding": undefined, + "contentMediaType": undefined, "default": undefined, - "type": "string", - "x-refsStack": Array [ + "deprecated": false, + "description": "", + "displayFormat": undefined, + "displayType": "string", + "enum": Array [], + "example": undefined, + "examples": undefined, + "externalDocs": undefined, + "format": undefined, + "isCircular": false, + "isPrimitive": true, + "maxItems": undefined, + "minItems": undefined, + "options": "<<>>", + "pattern": undefined, + "pointer": "#/components/schemas/Dog/properties/type", + "rawSchema": Object { + "default": undefined, + "type": "string", + "x-refsStack": Array [ + "#/components/schemas/Dog", + "#/components/schemas/Pet", + ], + }, + "readOnly": false, + "refsStack": Array [ + "#/components/schemas/Dog", "#/components/schemas/Dog", "#/components/schemas/Pet", - ], - }, - "readOnly": false, - "refsStack": Array [ - "#/components/schemas/Dog", - "#/components/schemas/Dog", - "#/components/schemas/Pet", - "#/components/schemas/Dog", - "#/components/schemas/Pet", - "#/components/schemas/Dog/properties/type", - ], - "schema": Object { - "default": undefined, - "type": "string", - "x-refsStack": Array [ "#/components/schemas/Dog", "#/components/schemas/Pet", + "#/components/schemas/Dog/properties/type", ], + "schema": Object { + "default": undefined, + "type": "string", + "x-refsStack": Array [ + "#/components/schemas/Dog", + "#/components/schemas/Pet", + ], + }, + "title": "", + "type": "string", + "typePrefix": "", + "writeOnly": false, }, - "title": "", - "type": "string", - "typePrefix": "", - "writeOnly": false, - }, + } } - } - isLast={true} - key="type" - renderDiscriminatorSwitch={[Function]} - showExamples={false} - /> - - + isLast={true} + key="type" + renderDiscriminatorSwitch={[Function]} + showExamples={false} + /> + + + `; diff --git a/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap b/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap index f98b667a4f..5e82223877 100644 --- a/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap @@ -159,7 +159,7 @@ exports[`FieldDetailsComponent renders correctly when field items have string ty [

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/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index 0cdd7f9e2a..e71bcd46c8 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -39,6 +39,8 @@ export interface RedocRawOptions { showObjectSchemaExamples?: boolean | string; showSecuritySchemeType?: boolean; hideSecuritySection?: boolean; + hideObjectTitle?: boolean | string; + hideObjectDescription?: boolean | string; unstable_ignoreMimeParameters?: boolean;