diff --git a/demo/openapi.yaml b/demo/openapi.yaml index d715155e..b91e3622 100644 --- a/demo/openapi.yaml +++ b/demo/openapi.yaml @@ -1083,6 +1083,10 @@ components: - available - pending - sold + x-enumDescriptions: + available: Available status + pending: Pending status + sold: Sold status petType: description: Type of a pet type: string diff --git a/src/components/Fields/EnumValues.tsx b/src/components/Fields/EnumValues.tsx index 21448ea5..a2667398 100644 --- a/src/components/Fields/EnumValues.tsx +++ b/src/components/Fields/EnumValues.tsx @@ -5,17 +5,29 @@ import { l } from '../../services/Labels'; import { OptionsContext } from '../OptionsProvider'; import styled from '../../styled-components'; import { RedocRawOptions } from '../../services/RedocNormalizedOptions'; +import { StyledMarkdownBlock } from '../Markdown/styled.elements'; +import { Markdown } from '../Markdown/Markdown'; export interface EnumValuesProps { - values: string[]; - isArrayType: boolean; + values?: string[] | { [name: string]: string }; + type: string | string[]; } export interface EnumValuesState { collapsed: boolean; } +const DescriptionEnumsBlock = styled(StyledMarkdownBlock)` + table { + margin-bottom: 0.2em; + } +`; + export class EnumValues extends React.PureComponent { + constructor(props: EnumValuesProps) { + super(props); + this.toggle = this.toggle.bind(this); + } state: EnumValuesState = { collapsed: true, }; @@ -27,54 +39,94 @@ export class EnumValues extends React.PureComponent ({ + value, + description, + })); // TODO: provide context interface in more elegant way const { enumSkipQuotes, maxDisplayedEnumValues } = this.context as RedocRawOptions; - if (!values.length) { + if (!enums.length) { return null; } const displayedItems = this.state.collapsed && maxDisplayedEnumValues - ? values.slice(0, maxDisplayedEnumValues) - : values; + ? enums.slice(0, maxDisplayedEnumValues) + : enums; - const showToggleButton = maxDisplayedEnumValues - ? values.length > maxDisplayedEnumValues - : false; + const showToggleButton = maxDisplayedEnumValues ? enums.length > maxDisplayedEnumValues : false; const toggleButtonText = maxDisplayedEnumValues ? collapsed - ? `… ${values.length - maxDisplayedEnumValues} more` + ? `… ${enums.length - maxDisplayedEnumValues} more` : 'Hide' : ''; return (
- - {isArrayType ? l('enumArray') : ''}{' '} - {values.length === 1 ? l('enumSingleValue') : l('enum')}: - {' '} - {displayedItems.map((value, idx) => { - const exampleValue = enumSkipQuotes ? String(value) : JSON.stringify(value); - return ( - - {exampleValue}{' '} - - ); - })} - {showToggleButton ? ( - { - this.toggle(); - }} - > - {toggleButtonText} - - ) : null} + {isDescriptionEnum ? ( + <> + + + + + + + + + + {(displayedItems as { value: string; description: string }[]).map( + ({ description, value }) => { + return ( + + + + + ); + }, + )} + +
+ + {type === 'array' ? l('enumArray') : ''}{' '} + {enums.length === 1 ? l('enumSingleValue') : l('enum')} + {' '} + + Description +
{value} + +
+
+ {showToggleButton ? ( + {toggleButtonText} + ) : null} + + ) : ( + <> + + {type === 'array' ? l('enumArray') : ''}{' '} + {values.length === 1 ? l('enumSingleValue') : l('enum')}: + {' '} + {displayedItems.map((value, idx) => { + const exampleValue = enumSkipQuotes ? String(value) : JSON.stringify(value); + return ( + + {exampleValue}{' '} + + ); + })} + {showToggleButton ? ( + {toggleButtonText} + ) : null} + + )}
); } diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 570c382f..19f58572 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -99,7 +99,7 @@ export const FieldDetailsComponent = observer((props: FieldProps) => { )} {!renderDiscriminatorSwitch && ( - + )}{' '} {renderedExamples} diff --git a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap index 48819982..27cb32d2 100644 --- a/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/DiscriminatorDropdown.test.tsx.snap @@ -79,12 +79,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -93,7 +94,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -102,8 +103,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -114,6 +115,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -292,7 +294,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog/properties/packSize", @@ -313,6 +314,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "number", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, FieldModel { @@ -351,12 +353,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -365,7 +368,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -374,8 +377,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -386,6 +389,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -564,7 +568,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog/properties/type", @@ -597,6 +600,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "string", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, ], @@ -610,12 +614,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -624,7 +629,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -633,8 +638,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -645,6 +650,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -823,7 +829,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog", @@ -878,6 +883,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "object", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, SchemaModel { "activeOneOf": 0, @@ -931,12 +937,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -945,7 +952,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -954,8 +961,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -966,6 +973,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -1144,7 +1152,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Cat/properties/type", @@ -1177,6 +1184,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "string", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, FieldModel { @@ -1215,12 +1223,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -1229,7 +1238,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -1238,8 +1247,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -1250,6 +1259,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -1428,7 +1438,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Cat/properties/packSize", @@ -1457,6 +1466,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "number", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, ], @@ -1470,12 +1480,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -1484,7 +1495,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -1493,8 +1504,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -1505,6 +1516,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -1683,7 +1695,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Cat", @@ -1743,6 +1754,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "object", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, ], "options": RedocNormalizedOptions { @@ -1750,12 +1762,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -1764,7 +1777,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -1773,8 +1786,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -1785,6 +1798,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -1963,7 +1977,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Pet", @@ -2003,6 +2016,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "object", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, } } @@ -2060,12 +2074,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -2074,7 +2089,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -2083,8 +2098,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -2095,6 +2110,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -2273,7 +2289,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog/properties/packSize", @@ -2294,6 +2309,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "number", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, FieldModel { @@ -2332,12 +2348,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -2346,7 +2363,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -2355,8 +2372,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -2367,6 +2384,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -2545,7 +2563,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog/properties/type", @@ -2578,6 +2595,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "string", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, }, ], @@ -2591,12 +2609,13 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "disableSearch": false, "downloadDefinitionUrl": undefined, "downloadFileName": undefined, + "downloadUrls": undefined, "enumSkipQuotes": false, "expandDefaultServerVariables": false, "expandResponses": {}, "expandSingleSchemaField": false, "generatedPayloadSamplesMaxDepth": 10, - "hideDownloadButton": false, + "hideDownloadButtons": false, "hideFab": false, "hideHostname": false, "hideRequestPayloadSample": false, @@ -2605,7 +2624,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "hideSecuritySection": false, "hideSingleRequestSampleTab": false, "ignoreNamedSchemas": Set {}, - "jsonSampleExpandLevel": 2, + "jsonSamplesExpandLevel": 2, "maxDisplayedEnumValues": undefined, "menuToggle": true, "minCharacterLengthToInitSearch": 3, @@ -2614,8 +2633,8 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "onlyRequiredInSamples": false, "pathInMiddlePanel": false, "payloadSampleIdx": 0, - "requiredPropsFirst": false, - "schemaExpansionLevel": 0, + "sanitize": false, + "schemasExpansionLevel": 0, "scrollYOffset": [Function], "showExtensions": false, "showObjectSchemaExamples": false, @@ -2626,6 +2645,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "sortEnumValuesAlphabetically": false, "sortOperationsAlphabetically": false, "sortPropsAlphabetically": false, + "sortRequiredPropsFirst": false, "sortTagsAlphabetically": false, "theme": { "breakpoints": { @@ -2804,7 +2824,6 @@ exports[`Components SchemaView discriminator should correctly render SchemaView }, }, "unstable_ignoreMimeParameters": false, - "untrustedSpec": false, }, "pattern": undefined, "pointer": "#/components/schemas/Dog", @@ -2859,6 +2878,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView "type": "object", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, } } /> @@ -2921,6 +2941,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat "type": "number", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, } } @@ -2994,6 +3015,7 @@ exports[`Components SchemaView discriminator should correctly render discriminat "type": "string", "typePrefix": "", "writeOnly": false, + "x-enumDescriptions": undefined, }, } } diff --git a/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap b/src/components/__tests__/__snapshots__/FieldDetails.test.tsx.snap index 5d6e6811..aa1cc03c 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 [ items diff --git a/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap b/src/components/__tests__/__snapshots__/SecurityRequirement.test.tsx.snap index 67c34782..cfea66c7 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__/fixtures/nestedEnumDescroptionSample.json b/src/services/__tests__/fixtures/nestedEnumDescroptionSample.json new file mode 100644 index 00000000..86108b01 --- /dev/null +++ b/src/services/__tests__/fixtures/nestedEnumDescroptionSample.json @@ -0,0 +1,24 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0", + "title": "Test" + }, + "components": { + "schemas": { + "Test": { + "type": "array", + "description": "test description", + "items": { + "type": "string", + "description": "test description", + "enum": ["authorize", "do-nothing"], + "x-enumDescriptions": { + "authorize-and-void": "Will create an authorize transaction in the amount/currency of the request, followed by a void", + "do-nothing": "Will do nothing, and return an approved `setup` transaction. This is the default behavior." + } + } + } + } + } +} diff --git a/src/services/__tests__/models/ApiInfo.test.ts b/src/services/__tests__/models/ApiInfo.test.ts index e446074e..9b9ed51e 100644 --- a/src/services/__tests__/models/ApiInfo.test.ts +++ b/src/services/__tests__/models/ApiInfo.test.ts @@ -142,7 +142,15 @@ describe('Models', () => { downloadUrls: [{ title: 'Openapi description', url: 'https:test.com/filename.yaml' }], }); const info = new ApiInfoModel(parser, opts); - expect(info.downloadLink).toEqual('https:test.com/filename.yaml'); + expect(info.downloadUrls).toMatchInlineSnapshot(` + [ + { + "title": "Openapi description", + "url": "https:test.com/filename.yaml", + }, + ] + `); + expect(info.downloadFileName).toMatchInlineSnapshot(`"openapi.json"`); }); test('should correctly populate download link and download file name', () => { @@ -158,15 +166,29 @@ describe('Models', () => { downloadFileName: 'test.yaml', }); const info = new ApiInfoModel(parser, opts); - expect(info.downloadLink).toEqual('https:test.com/filename.yaml'); - expect(info.downloadFileName).toEqual('test.yaml'); + expect(info.downloadUrls).toMatchInlineSnapshot(` + [ + { + "title": "Download", + "url": "https:test.com/filename.yaml", + }, + ] + `); + expect(info.downloadFileName).toMatchInlineSnapshot(`"test.yaml"`); const opts2 = new RedocNormalizedOptions({ - downloadUrls: [{ title: 'test.yaml', url: 'https:test.com/filename.yaml' }], + downloadUrls: [{ title: 'Download file', url: 'https:test.com/filename.yaml' }], }); const info2 = new ApiInfoModel(parser, opts2); - expect(info2.downloadLink).toEqual('https:test.com/filename.yaml'); - expect(info2.downloadFileName).toEqual('test.yaml'); + expect(info2.downloadUrls).toMatchInlineSnapshot(` + [ + { + "title": "Download file", + "url": "https:test.com/filename.yaml", + }, + ] + `); + expect(info2.downloadFileName).toMatchInlineSnapshot(`"openapi.json"`); }); }); }); diff --git a/src/services/__tests__/models/Schema.test.ts b/src/services/__tests__/models/Schema.test.ts index 9dab8a1b..514599d9 100644 --- a/src/services/__tests__/models/Schema.test.ts +++ b/src/services/__tests__/models/Schema.test.ts @@ -13,6 +13,17 @@ describe('Models', () => { describe('Schema', () => { let parser; + test('parsing nested x-enumDescription', () => { + const spec = require('../fixtures/nestedEnumDescroptionSample.json'); + parser = new OpenAPIParser(spec, undefined, opts); + const testSchema = spec.components.schemas.Test; + const schemaModel = new SchemaModel(parser, testSchema, '', opts); + + expect(schemaModel['x-enumDescriptions']).toStrictEqual( + testSchema.items['x-enumDescriptions'], + ); + }); + test('discriminator with one field', () => { const spec = require('../fixtures/discriminator.json'); parser = new OpenAPIParser(spec, undefined, opts); diff --git a/src/services/models/ApiInfo.ts b/src/services/models/ApiInfo.ts index 7a7d6db9..325161fe 100644 --- a/src/services/models/ApiInfo.ts +++ b/src/services/models/ApiInfo.ts @@ -34,7 +34,7 @@ export class ApiInfoModel implements OpenAPIInfo { } this.downloadUrls = this.getDownloadUrls(); - this.downloadFileName = this.options.downloadFileName || 'openapi.json'; + this.downloadFileName = this.getDownloadFileName(); } private getDownloadUrls() { return ( @@ -68,4 +68,11 @@ export class ApiInfoModel implements OpenAPIInfo { return window.URL.createObjectURL(blob); } } + + private getDownloadFileName(): string | undefined { + if (!this.parser.specUrl && !this.options.downloadDefinitionUrl) { + return this.options.downloadFileName || 'openapi.json'; + } + return this.options.downloadFileName; + } } diff --git a/src/services/models/Schema.ts b/src/services/models/Schema.ts index 2a9def5d..a07e0719 100644 --- a/src/services/models/Schema.ts +++ b/src/services/models/Schema.ts @@ -65,6 +65,7 @@ export class SchemaModel { rawSchema: OpenAPISchema; schema: MergedOpenAPISchema; extensions?: Record; + 'x-enumDescriptions': { [name: string]: string }; const: any; contentEncoding?: string; contentMediaType?: string; @@ -122,6 +123,7 @@ export class SchemaModel { this.type = schema.type || detectType(schema); this.format = schema.format; this.enum = schema.enum || []; + this['x-enumDescriptions'] = schema['x-enumDescriptions']; this.example = schema.example; this.examples = schema.examples; this.deprecated = !!schema.deprecated; @@ -221,6 +223,7 @@ export class SchemaModel { } if (this.items?.isPrimitive) { this.enum = this.items.enum; + this['x-enumDescriptions'] = this.items['x-enumDescriptions']; } if (isArray(this.type)) { const filteredType = this.type.filter(item => item !== 'array'); diff --git a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap index cefc7d37..21942671 100644 --- a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap +++ b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap @@ -311,6 +311,11 @@ exports[`#loadAndBundleSpec should load And Bundle Spec demo/openapi.yaml 1`] = "sold", ], "type": "string", + "x-enumDescriptions": { + "available": "Available status", + "pending": "Pending status", + "sold": "Sold status", + }, }, "tags": { "description": "Tags attached to the pet", diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 1d3a33c5..4c9b8395 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -654,6 +654,7 @@ export function isRedocExtension(key: string): boolean { 'x-codeSamples': true, 'x-displayName': true, 'x-examples': true, + 'x-enumDescriptions': true, 'x-ignoredHeaderParameters': true, 'x-logo': true, 'x-nullable': true,