mirror of
https://github.com/Redocly/redoc.git
synced 2025-08-06 21:30:21 +03:00
Merge 35395bf609
into 92387bc653
This commit is contained in:
commit
b12e981367
8
e2e/expandSchemas.html
Normal file
8
e2e/expandSchemas.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
|
||||
<body>
|
||||
<redoc spec-url="../demo/openapi.yaml" expand-schemas="true"></redoc>
|
||||
<script src="../bundles/redoc.standalone.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
17
e2e/integration/expandSchemas.e2e.ts
Normal file
17
e2e/integration/expandSchemas.e2e.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
describe('Schemas', () => {
|
||||
it('expandSchemas != true', () => {
|
||||
cy.visit('e2e/standalone.html');
|
||||
|
||||
cy.get('.api-content')
|
||||
.find('.expanded')
|
||||
.should('have.length', 0);
|
||||
});
|
||||
|
||||
it('expandSchemas == true', () => {
|
||||
cy.visit('e2e/expandSchemas.html');
|
||||
|
||||
cy.get('.api-content')
|
||||
.find('.expanded')
|
||||
.should('have.length', 146);
|
||||
});
|
||||
});
|
|
@ -12,11 +12,12 @@ export class ResponseView extends React.Component<{ response: ResponseModel }> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { headers, type, summary, description, code, expanded, content } = this.props.response;
|
||||
const { extensions, headers, type, summary, description, code, expanded, content } = this.props.response;
|
||||
const mimes =
|
||||
content === undefined ? [] : content.mediaTypes.filter(mime => mime.schema !== undefined);
|
||||
|
||||
const empty = headers.length === 0 && mimes.length === 0 && !description;
|
||||
const empty = (!extensions || Object.keys(extensions).length === 0) &&
|
||||
headers.length === 0 && mimes.length === 0 && !description;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
@ -7,15 +7,17 @@ import { DropdownOrLabel } from '../DropdownOrLabel/DropdownOrLabel';
|
|||
import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
||||
import { Schema } from '../Schema';
|
||||
|
||||
import { Extensions } from '../Fields/Extensions';
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { ResponseHeaders } from './ResponseHeaders';
|
||||
|
||||
export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> {
|
||||
render() {
|
||||
const { description, headers, content } = this.props.response;
|
||||
const { description, extensions, headers, content } = this.props.response;
|
||||
return (
|
||||
<>
|
||||
{description && <Markdown source={description} />}
|
||||
<Extensions extensions={extensions} />
|
||||
<ResponseHeaders headers={headers} />
|
||||
<MediaTypesSwitch content={content} renderDropdown={this.renderDropdown}>
|
||||
{({ schema }) => {
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface RedocRawOptions {
|
|||
expandDefaultServerVariables?: boolean;
|
||||
maxDisplayedEnumValues?: number;
|
||||
ignoreNamedSchemas?: string[] | string;
|
||||
expandSchemas?: boolean;
|
||||
hideSchemaPattern?: boolean;
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,10 @@ export class RedocNormalizedOptions {
|
|||
return !!value;
|
||||
}
|
||||
|
||||
static normalizeExpandSchemas(value: RedocRawOptions['expandSchemas']): boolean {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
static normalizeScrollYOffset(value: RedocRawOptions['scrollYOffset']): () => number {
|
||||
// just number is not valid selector and leads to crash so checking if isNumeric here
|
||||
if (typeof value === 'string' && !isNumeric(value)) {
|
||||
|
@ -195,6 +200,7 @@ export class RedocNormalizedOptions {
|
|||
maxDisplayedEnumValues?: number;
|
||||
|
||||
ignoreNamedSchemas: Set<string>;
|
||||
expandSchemas: boolean;
|
||||
hideSchemaPattern: boolean;
|
||||
|
||||
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
|
||||
|
@ -256,6 +262,7 @@ export class RedocNormalizedOptions {
|
|||
? raw.ignoreNamedSchemas
|
||||
: raw.ignoreNamedSchemas?.split(',').map((s) => s.trim());
|
||||
this.ignoreNamedSchemas = new Set(ignoreNamedSchemas);
|
||||
this.expandSchemas = RedocNormalizedOptions.normalizeExpandSchemas(raw.expandSchemas);
|
||||
this.hideSchemaPattern = argValueToBoolean(raw.hideSchemaPattern);
|
||||
}
|
||||
}
|
||||
|
|
20
src/services/__tests__/fixtures/expandSchemas.json
Normal file
20
src/services/__tests__/fixtures/expandSchemas.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"version": "1.0",
|
||||
"title": "Foo"
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Foo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,5 +31,12 @@ describe('Models', () => {
|
|||
const resp = new ResponseModel(parser, 'default', true, {}, opts);
|
||||
expect(resp.type).toEqual('error');
|
||||
});
|
||||
|
||||
test('ensure extensions are shown if showExtensions is true', () => {
|
||||
const options = new RedocNormalizedOptions({ showExtensions: true });
|
||||
const resp = new ResponseModel(parser, 'default', true, { 'x-example': {a: 1} } as any, options);
|
||||
expect(Object.keys(resp.extensions).length).toEqual(1);
|
||||
expect(resp.extensions['x-example']).toEqual({a: 1});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -40,5 +40,25 @@ describe('Models', () => {
|
|||
expect(schema.oneOf).toHaveLength(2);
|
||||
expect(schema.displayType).toBe('(Array of strings or numbers) or string');
|
||||
});
|
||||
|
||||
test('expandSchemas != true', () => {
|
||||
const spec = require('../fixtures/expandSchemas.json');
|
||||
parser = new OpenAPIParser(spec, undefined, opts);
|
||||
const schema = new SchemaModel(parser, spec.components.schemas.Foo, '', opts);
|
||||
expect(schema.fields).toHaveLength(2);
|
||||
expect(schema.fields![0].expanded).toEqual(false);
|
||||
expect(schema.fields![1].expanded).toEqual(false);
|
||||
});
|
||||
|
||||
test('expandSchemas == true', () => {
|
||||
const opts = new RedocNormalizedOptions({ expandSchemas: true});
|
||||
|
||||
const spec = require('../fixtures/expandSchemas.json');
|
||||
parser = new OpenAPIParser(spec, undefined, opts);
|
||||
const schema = new SchemaModel(parser, spec.components.schemas.Foo, '', opts);
|
||||
expect(schema.fields).toHaveLength(2);
|
||||
expect(schema.fields![0].expanded).toEqual(true);
|
||||
expect(schema.fields![1].expanded).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,10 @@ import { action, observable, makeObservable } from 'mobx';
|
|||
|
||||
import { OpenAPIResponse, Referenced } from '../../types';
|
||||
|
||||
import { getStatusCodeType } from '../../utils';
|
||||
import {
|
||||
extractExtensions,
|
||||
getStatusCodeType,
|
||||
} from '../../utils';
|
||||
import { OpenAPIParser } from '../OpenAPIParser';
|
||||
import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
|
||||
import { FieldModel } from './Field';
|
||||
|
@ -19,6 +22,8 @@ export class ResponseModel {
|
|||
type: string;
|
||||
headers: FieldModel[] = [];
|
||||
|
||||
extensions: Record<string, any>;
|
||||
|
||||
constructor(
|
||||
parser: OpenAPIParser,
|
||||
code: string,
|
||||
|
@ -54,6 +59,10 @@ export class ResponseModel {
|
|||
return new FieldModel(parser, { ...header, name }, '', options);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.showExtensions) {
|
||||
this.extensions = extractExtensions(info, options.showExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
@ -363,7 +363,7 @@ function buildFields(
|
|||
const required =
|
||||
schema.required === undefined ? false : schema.required.indexOf(fieldName) > -1;
|
||||
|
||||
return new FieldModel(
|
||||
const fieldModel = new FieldModel(
|
||||
parser,
|
||||
{
|
||||
name: fieldName,
|
||||
|
@ -376,6 +376,8 @@ function buildFields(
|
|||
$ref + '/properties/' + fieldName,
|
||||
options,
|
||||
);
|
||||
fieldModel.expanded = options.expandSchemas;
|
||||
return fieldModel;
|
||||
});
|
||||
|
||||
if (options.sortPropsAlphabetically) {
|
||||
|
@ -387,22 +389,22 @@ function buildFields(
|
|||
}
|
||||
|
||||
if (typeof additionalProps === 'object' || additionalProps === true) {
|
||||
fields.push(
|
||||
new FieldModel(
|
||||
parser,
|
||||
{
|
||||
name: (typeof additionalProps === 'object'
|
||||
? additionalProps['x-additionalPropertiesName'] || 'property name'
|
||||
: 'property name'
|
||||
).concat('*'),
|
||||
required: false,
|
||||
schema: additionalProps === true ? {} : additionalProps,
|
||||
kind: 'additionalProperties',
|
||||
},
|
||||
$ref + '/additionalProperties',
|
||||
options,
|
||||
),
|
||||
const fieldModel = new FieldModel(
|
||||
parser,
|
||||
{
|
||||
name: (typeof additionalProps === 'object'
|
||||
? additionalProps['x-additionalPropertiesName'] || 'property name'
|
||||
: 'property name'
|
||||
).concat('*'),
|
||||
required: false,
|
||||
schema: additionalProps === true ? {} : additionalProps,
|
||||
kind: 'additionalProperties',
|
||||
},
|
||||
$ref + '/additionalProperties',
|
||||
options,
|
||||
);
|
||||
fieldModel.expanded = options.expandSchemas;
|
||||
fields.push(fieldModel);
|
||||
}
|
||||
|
||||
return fields;
|
||||
|
|
2
src/types/open-api.d.ts
vendored
2
src/types/open-api.d.ts
vendored
|
@ -187,7 +187,7 @@ export interface OpenAPIRequestBody {
|
|||
}
|
||||
|
||||
export interface OpenAPIResponses {
|
||||
[code: string]: OpenAPIResponse;
|
||||
[code: string]: Referenced<OpenAPIResponse>;
|
||||
}
|
||||
|
||||
export interface OpenAPIResponse {
|
||||
|
|
Loading…
Reference in New Issue
Block a user