add section menus for tags and object description

This commit is contained in:
Dimitar Nanov 2018-10-19 19:53:19 +03:00 committed by Roman Hotsiy
parent 7db7d4fc91
commit 4359724434
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
6 changed files with 118 additions and 7 deletions

View File

@ -58,9 +58,21 @@ externalDocs:
url: 'https://github.com/Rebilly/generator-openapi-repo'
tags:
- name: pet
description: Everything about your Pets
description: |
Everything about your Pets
## The Pet Object
<object-description schemaRef="#/components/schemas/Pet" />
- name: store
description: Access to Petstore orders
description: |
Access to Petstore orders
## The Order Object
<object-description schemaRef="#/components/schemas/Order" examplesRef="#/components/examples/Order" />
- name: user
description: Operations about user
x-tagGroups:
@ -926,3 +938,10 @@ components:
type: apiKey
name: api_key
in: header
examples:
Order:
value:
quantity: 1,
shipDate: 2018-10-19T16:46:45Z,
status: placed,
complete: false

View File

@ -0,0 +1,64 @@
import * as React from 'react';
import { Schema } from '../Schema';
import { MiddlePanel, Row, Section, DarkRightPanel } from '../../common-elements';
import { OpenAPIParser, RedocNormalizedOptions, MediaTypeModel } from '../../services';
import { MediaTypeSamples } from '../PayloadSamples/MediaTypeSamples';
import { OpenAPIMediaType } from '../../types';
export interface ObjectDescriptionProps {
schemaRef: string;
examplesRef?: string;
parser: OpenAPIParser;
options: RedocNormalizedOptions;
}
export class ObjectDescription extends React.PureComponent<ObjectDescriptionProps> {
private mediaModel: MediaTypeModel;
constructor(props: ObjectDescriptionProps) {
super(props);
this.mediaModel = ObjectDescription.getMediaModel(this.props);
}
render() {
return (
<Section>
<Row>
<MiddlePanel>
<Schema skipWriteOnly={true} key="schema" schema={this.mediaModel.schema} />
</MiddlePanel>
<DarkRightPanel>
<MediaTypeSamples mediaType={this.mediaModel} />
</DarkRightPanel>
</Row>
</Section>
);
}
private static getMediaType(schemaRef, examplesRef): OpenAPIMediaType {
if (!schemaRef) return {};
const info: OpenAPIMediaType = {
schema: { $ref: schemaRef },
};
if (examplesRef) info.examples = { object: { $ref: examplesRef } };
return info;
}
private static getMediaModel({
schemaRef,
examplesRef,
parser,
options,
}: ObjectDescriptionProps) {
return new MediaTypeModel(
parser,
'json',
false,
ObjectDescription.getMediaType(schemaRef, examplesRef),
options,
);
}
}

View File

@ -10,8 +10,12 @@ import { RedocNormalizedOptions, RedocRawOptions } from './RedocNormalizedOption
import { ScrollService } from './ScrollService';
import { SearchStore } from './SearchStore';
import { ObjectDescription } from '../components/ObjectDescription/ObjectDescription';
import { SecurityDefs } from '../components/SecuritySchemes/SecuritySchemes';
import { SECURITY_DEFINITIONS_COMPONENT_NAME } from '../utils/openapi';
import {
SECURITY_DEFINITIONS_COMPONENT_NAME,
OBJECT_DEFINTION_COMPONENT_NAME,
} from '../utils/openapi';
export interface StoreState {
menu: {
@ -151,5 +155,13 @@ const DEFAULT_OPTIONS: RedocRawOptions = {
securitySchemes: store.spec.securitySchemes,
}),
},
[OBJECT_DEFINTION_COMPONENT_NAME]: {
component: ObjectDescription,
propsSelector: (store: AppStore) => ({
securitySchemes: store.spec.securitySchemes,
parser: store.spec.parser,
options: store.options,
}),
},
},
};

View File

@ -42,7 +42,7 @@ export class MenuBuilder {
const items: ContentItemModel[] = [];
const tagsMap = MenuBuilder.getTagsWithOperations(spec);
items.push(...MenuBuilder.addMarkdownItems(spec.info.description || '', options));
items.push(...MenuBuilder.addMarkdownItems(spec.info.description || '', undefined, options));
if (spec['x-tagGroups'] && spec['x-tagGroups'].length > 0) {
items.push(
...MenuBuilder.getTagGroupsItems(parser, undefined, spec['x-tagGroups'], tagsMap, options),
@ -59,6 +59,7 @@ export class MenuBuilder {
*/
static addMarkdownItems(
description: string,
parent: GroupModel | undefined,
options: RedocNormalizedOptions,
): ContentItemModel[] {
const renderer = new MarkdownRenderer(options);
@ -82,7 +83,7 @@ export class MenuBuilder {
return group;
});
return mapHeadingsDeep(undefined, headings);
return mapHeadingsDeep(parent, headings, 1);
}
/**
@ -144,15 +145,22 @@ export class MenuBuilder {
}
const item = new GroupModel('tag', tag, parent);
item.depth = GROUP_DEPTH + 1;
item.items = this.getOperationsItems(parser, item, tag, item.depth + 1, options);
// don't put empty tag into content, instead put its operations
if (tag.name === '') {
const items = this.getOperationsItems(parser, undefined, tag, item.depth + 1, options);
const items = [
...MenuBuilder.addMarkdownItems(tag.description || '', item, options),
...this.getOperationsItems(parser, undefined, tag, item.depth + 1, options),
];
res.push(...items);
continue;
}
item.items = [
...MenuBuilder.addMarkdownItems(tag.description || '', item, options),
...this.getOperationsItems(parser, item, tag, item.depth + 1, options),
];
res.push(item);
}
return res;

View File

@ -40,7 +40,14 @@ export class GroupModel implements IMenuItem {
this.type = type;
this.name = tagOrGroup['x-displayName'] || tagOrGroup.name;
this.level = (tagOrGroup as MarkdownHeading).level || 1;
// remove sections from markdown, same as in ApiInfo
this.description = tagOrGroup.description || '';
const firstHeadingLinePos = this.description.search(/^##?\s+/m);
if (firstHeadingLinePos > -1) {
this.description = this.description.substring(0, firstHeadingLinePos);
}
this.parent = parent;
this.externalDocs = (tagOrGroup as OpenAPITag).externalDocs;

View File

@ -495,6 +495,7 @@ export function normalizeServers(
});
}
export const OBJECT_DEFINTION_COMPONENT_NAME = 'object-description';
export const SECURITY_DEFINITIONS_COMPONENT_NAME = 'security-definitions';
export let SECURITY_SCHEMES_SECTION_PREFIX = 'section/Authentication/';
export function setSecuritySchemePrefix(prefix: string) {