mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-22 00:26:34 +03:00
feat: show minProperties maxProperties (#2015)
This commit is contained in:
parent
0aafee1131
commit
82712c5b40
|
@ -88,7 +88,7 @@ paths:
|
|||
parameters:
|
||||
- name: Accept-Language
|
||||
in: header
|
||||
description: "The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US"
|
||||
description: 'The language you prefer for messages. Supported values are en-AU, en-CA, en-GB, en-US'
|
||||
example: en-US
|
||||
required: false
|
||||
schema:
|
||||
|
@ -254,7 +254,7 @@ paths:
|
|||
required: false
|
||||
schema:
|
||||
type: string
|
||||
example: "Bearer <TOKEN>"
|
||||
example: 'Bearer <TOKEN>'
|
||||
- name: petId
|
||||
in: path
|
||||
description: Pet id to delete
|
||||
|
@ -401,6 +401,7 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
minProperties: 2
|
||||
additionalProperties:
|
||||
type: integer
|
||||
format: int32
|
||||
|
@ -429,7 +430,7 @@ paths:
|
|||
application/json:
|
||||
example:
|
||||
status: 400
|
||||
message: "Invalid Order"
|
||||
message: 'Invalid Order'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
|
@ -877,11 +878,11 @@ paths:
|
|||
type: string
|
||||
examples:
|
||||
response:
|
||||
value: <Message> OK </Message>
|
||||
value: <Message> OK </Message>
|
||||
text/plain:
|
||||
examples:
|
||||
response:
|
||||
value: OK
|
||||
value: OK
|
||||
'400':
|
||||
description: Invalid username/password supplied
|
||||
/user/logout:
|
||||
|
@ -1027,8 +1028,8 @@ components:
|
|||
properties:
|
||||
id:
|
||||
externalDocs:
|
||||
description: "Find more info here"
|
||||
url: "https://example.com"
|
||||
description: 'Find more info here'
|
||||
url: 'https://example.com'
|
||||
description: Pet ID
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/Id'
|
||||
|
@ -1201,7 +1202,7 @@ x-webhooks:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
$ref: '#/components/schemas/Pet'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: Return a 200 status to indicate that the data was received successfully
|
||||
|
|
|
@ -10,6 +10,7 @@ import { MediaTypesSwitch } from '../MediaTypeSwitch/MediaTypesSwitch';
|
|||
import { Schema } from '../Schema';
|
||||
|
||||
import { Markdown } from '../Markdown/Markdown';
|
||||
import { ConstraintsView } from '../Fields/FieldContstraints';
|
||||
|
||||
function safePush(obj, prop, item) {
|
||||
if (!obj[prop]) {
|
||||
|
@ -79,6 +80,7 @@ export function BodyContent(props: {
|
|||
return (
|
||||
<>
|
||||
{description !== undefined && <Markdown source={description} />}
|
||||
<ConstraintsView constraints={schema?.constraints || []} />
|
||||
<Schema
|
||||
skipReadOnly={isRequestType}
|
||||
skipWriteOnly={!isRequestType}
|
||||
|
|
|
@ -10,6 +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';
|
||||
|
||||
export class ResponseDetails extends React.PureComponent<{ response: ResponseModel }> {
|
||||
render() {
|
||||
|
@ -21,7 +22,12 @@ export class ResponseDetails extends React.PureComponent<{ response: ResponseMod
|
|||
<ResponseHeaders headers={headers} />
|
||||
<MediaTypesSwitch content={content} renderDropdown={this.renderDropdown}>
|
||||
{({ schema }) => {
|
||||
return <Schema skipWriteOnly={true} key="schema" schema={schema} />;
|
||||
return (
|
||||
<>
|
||||
<ConstraintsView constraints={schema?.constraints || []} />
|
||||
<Schema skipWriteOnly={true} key="schema" schema={schema} />
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</MediaTypesSwitch>
|
||||
</>
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from '../../common-elements/schema';
|
||||
import { Badge } from '../../common-elements/shelfs';
|
||||
import { SchemaModel } from '../../services/models';
|
||||
import { ConstraintsView } from '../Fields/FieldContstraints';
|
||||
import { Schema, SchemaProps } from './Schema';
|
||||
|
||||
export interface OneOfButtonProps {
|
||||
|
@ -47,6 +48,8 @@ export class OneOfSchema extends React.Component<SchemaProps> {
|
|||
if (oneOf === undefined) {
|
||||
return null;
|
||||
}
|
||||
const activeSchema = oneOf[schema.activeOneOf];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<OneOfLabel> {schema.oneOfType} </OneOfLabel>
|
||||
|
@ -58,7 +61,8 @@ export class OneOfSchema extends React.Component<SchemaProps> {
|
|||
<div>
|
||||
{oneOf[schema.activeOneOf].deprecated && <Badge type="warning">Deprecated</Badge>}
|
||||
</div>
|
||||
<Schema {...this.props} schema={oneOf[schema.activeOneOf]} />
|
||||
<ConstraintsView constraints={activeSchema.constraints} />
|
||||
<Schema {...this.props} schema={activeSchema} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -53,5 +53,30 @@ describe('Components', () => {
|
|||
expect(component.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Show minProperties/maxProperties constraints oneOf', () => {
|
||||
const schema = new SchemaModel(
|
||||
parser,
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
description: 'Test description',
|
||||
minProperties: 1,
|
||||
maxProperties: 1,
|
||||
additionalProperties: {
|
||||
type: 'string',
|
||||
description: 'The name and value o',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
'',
|
||||
options,
|
||||
);
|
||||
|
||||
const component = shallow(withTheme(<Schema schema={schema} />));
|
||||
expect(component.html().includes('= 1 properties')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
67
src/components/__tests__/Schema.test.tsx
Normal file
67
src/components/__tests__/Schema.test.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* tslint:disable:no-implicit-dependencies */
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Schema } from '../';
|
||||
import { OpenAPIParser, SchemaModel } from '../../services';
|
||||
import { RedocNormalizedOptions } from '../../services/RedocNormalizedOptions';
|
||||
import { withTheme } from '../testProviders';
|
||||
|
||||
const options = new RedocNormalizedOptions({});
|
||||
describe('Components', () => {
|
||||
describe('SchemaView', () => {
|
||||
const parser = new OpenAPIParser(
|
||||
{ openapi: '3.0', info: { title: 'test', version: '0' }, paths: {} },
|
||||
undefined,
|
||||
options,
|
||||
);
|
||||
|
||||
describe('Show minProperties/maxProperties constraints', () => {
|
||||
const schema = new SchemaModel(
|
||||
parser,
|
||||
{
|
||||
properties: {
|
||||
name: {
|
||||
type: 'object',
|
||||
minProperties: 1,
|
||||
properties: {
|
||||
address: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'',
|
||||
options,
|
||||
);
|
||||
const component = shallow(withTheme(<Schema schema={schema} />));
|
||||
expect(component.html().includes('non-empty')).toBe(true);
|
||||
});
|
||||
|
||||
describe('Show range minProperties/maxProperties constraints', () => {
|
||||
const schema = new SchemaModel(
|
||||
parser,
|
||||
{
|
||||
properties: {
|
||||
name: {
|
||||
type: 'object',
|
||||
minProperties: 2,
|
||||
maxProperties: 10,
|
||||
additionalProperties: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'',
|
||||
options,
|
||||
);
|
||||
it('should includes [ 2 .. 10 ] properties', () => {
|
||||
const component = shallow(withTheme(<Schema schema={schema} />));
|
||||
expect(component.html().includes('[ 2 .. 10 ] properties')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -966,6 +966,7 @@ try {
|
|||
"format": "int32",
|
||||
"type": "integer",
|
||||
},
|
||||
"minProperties": 2,
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -553,7 +553,7 @@ describe('Utils', () => {
|
|||
});
|
||||
|
||||
it('should have a humanized constraint when minItems and maxItems are the same', () => {
|
||||
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('7 items');
|
||||
expect(humanizeConstraints(itemConstraintSchema(7, 7))).toContain('= 7 items');
|
||||
});
|
||||
|
||||
it('should have a humanized constraint when justMinItems is set, and it is equal to 1', () => {
|
||||
|
|
|
@ -423,7 +423,7 @@ function humanizeRangeConstraint(
|
|||
let stringRange;
|
||||
if (min !== undefined && max !== undefined) {
|
||||
if (min === max) {
|
||||
stringRange = `${min} ${description}`;
|
||||
stringRange = `= ${min} ${description}`;
|
||||
} else {
|
||||
stringRange = `[ ${min} .. ${max} ] ${description}`;
|
||||
}
|
||||
|
@ -476,6 +476,15 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
|
|||
res.push(arrayRange);
|
||||
}
|
||||
|
||||
const propertiesRange = humanizeRangeConstraint(
|
||||
'properties',
|
||||
schema.minProperties,
|
||||
schema.maxProperties,
|
||||
);
|
||||
if (propertiesRange !== undefined) {
|
||||
res.push(propertiesRange);
|
||||
}
|
||||
|
||||
const multipleOfConstraint = humanizeMultipleOfConstraint(schema.multipleOf);
|
||||
if (multipleOfConstraint !== undefined) {
|
||||
res.push(multipleOfConstraint);
|
||||
|
|
Loading…
Reference in New Issue
Block a user