feat: add jsonrpc support

This commit is contained in:
jun097kim 2020-11-20 09:49:44 +09:00
parent c6b7d567d9
commit c160fbd991
9 changed files with 37 additions and 18 deletions

View File

@ -22,6 +22,7 @@ export interface EndpointProps {
hideHostname?: boolean; hideHostname?: boolean;
inverted?: boolean; inverted?: boolean;
compact?: boolean; compact?: boolean;
isJsonRpc?: boolean;
} }
export interface EndpointState { export interface EndpointState {
@ -41,7 +42,7 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
}; };
render() { render() {
const { operation, inverted, hideHostname } = this.props; const { operation, inverted, hideHostname, isJsonRpc } = this.props;
const { expanded } = this.state; const { expanded } = this.state;
// TODO: highlight server variables, e.g. https://{user}.test.com // TODO: highlight server variables, e.g. https://{user}.test.com
@ -80,7 +81,7 @@ export class Endpoint extends React.Component<EndpointProps, EndpointState> {
: basePath : basePath
: normalizedUrl} : normalizedUrl}
</span> </span>
{operation.path} {!!isJsonRpc ? `/json` : operation.path}
</ServerUrl> </ServerUrl>
</SelectOnClick> </SelectOnClick>
</ServerItem> </ServerItem>

View File

@ -37,7 +37,7 @@ export class Operation extends React.Component<OperationProps> {
render() { render() {
const { operation } = this.props; const { operation } = this.props;
const { name: summary, description, deprecated, externalDocs, isWebhook } = operation; const { name: summary, description, deprecated, externalDocs, isWebhook, isJsonRpc } = operation;
const hasDescription = !!(description || externalDocs); const hasDescription = !!(description || externalDocs);
return ( return (
@ -49,9 +49,10 @@ export class Operation extends React.Component<OperationProps> {
<ShareLink to={operation.id} /> <ShareLink to={operation.id} />
{summary} {deprecated && <Badge type="warning"> Deprecated </Badge>} {summary} {deprecated && <Badge type="warning"> Deprecated </Badge>}
{isWebhook && <Badge type="primary"> Webhook </Badge>} {isWebhook && <Badge type="primary"> Webhook </Badge>}
{isJsonRpc && <Badge type="primary"> JSON-RPC </Badge>}
</H2> </H2>
{options.pathInMiddlePanel && !isWebhook && ( {options.pathInMiddlePanel && !isWebhook && (
<Endpoint operation={operation} inverted={true} /> <Endpoint operation={operation} inverted={true} isJsonRpc={isJsonRpc} />
)} )}
{hasDescription && ( {hasDescription && (
<Description> <Description>
@ -66,7 +67,7 @@ export class Operation extends React.Component<OperationProps> {
<CallbacksList callbacks={operation.callbacks} /> <CallbacksList callbacks={operation.callbacks} />
</MiddlePanel> </MiddlePanel>
<DarkRightPanel> <DarkRightPanel>
{!options.pathInMiddlePanel && !isWebhook && <Endpoint operation={operation} />} {!options.pathInMiddlePanel && (!isWebhook || !isJsonRpc) && <Endpoint operation={operation} isJsonRpc={isJsonRpc} />}
<RequestSamples operation={operation} /> <RequestSamples operation={operation} />
<ResponseSamples operation={operation} /> <ResponseSamples operation={operation} />
<CallbackSamples callbacks={operation.callbacks} /> <CallbackSamples callbacks={operation.callbacks} />

View File

@ -91,11 +91,7 @@ export class OperationMenuItemContent extends React.Component<OperationMenuItemC
deprecated={item.deprecated} deprecated={item.deprecated}
ref={this.ref} ref={this.ref}
> >
{item.isWebhook ? ( {this.renderOperationBadge(item)}
<OperationBadge type="hook">{l('webhook')}</OperationBadge>
) : (
<OperationBadge type={item.httpVerb}>{shortenHTTPVerb(item.httpVerb)}</OperationBadge>
)}
<MenuItemTitle width="calc(100% - 38px)"> <MenuItemTitle width="calc(100% - 38px)">
{item.name} {item.name}
{this.props.children} {this.props.children}
@ -103,4 +99,14 @@ export class OperationMenuItemContent extends React.Component<OperationMenuItemC
</MenuItemLabel> </MenuItemLabel>
); );
} }
renderOperationBadge(item: OperationModel) {
if (item.isWebhook) {
return <OperationBadge type="hook">{l('webhook')}</OperationBadge>
} else if (item.isJsonRpc) {
return <OperationBadge type="rpc">{l('jsonrpc')}</OperationBadge>;
} else {
return <OperationBadge type={item.httpVerb}>{shortenHTTPVerb(item.httpVerb)}</OperationBadge>
}
}
} }

View File

@ -7,7 +7,7 @@ import styled, { css, ResolvedThemeInterface } from '../../styled-components';
export const OperationBadge = styled.span.attrs((props: { type: string }) => ({ export const OperationBadge = styled.span.attrs((props: { type: string }) => ({
className: `operation-type ${props.type}`, className: `operation-type ${props.type}`,
}))<{ type: string }>` }))<{ type: string }>`
width: 9ex; width: 15ex;
display: inline-block; display: inline-block;
height: ${props => props.theme.typography.code.fontSize}; height: ${props => props.theme.typography.code.fontSize};
line-height: ${props => props.theme.typography.code.fontSize}; line-height: ${props => props.theme.typography.code.fontSize};
@ -138,6 +138,7 @@ export const MenuItemLabel = styled.label.attrs((props: MenuItemLabelType) => ({
(type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''} (type === 'section' && depth > 1 && 'padding-left: ' + theme.spacing.unit * 8 + 'px;') || ''}
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
font-family: ${props => props.theme.typography.headings.fontFamily}; font-family: ${props => props.theme.typography.headings.fontFamily};
${props => menuItemDepth[props.depth]}; ${props => menuItemDepth[props.depth]};
background-color: ${props => (props.active ? menuItemActiveBg(props.depth, props) : '')}; background-color: ${props => (props.active ? menuItemActiveBg(props.depth, props) : '')};

View File

@ -9,6 +9,7 @@ export interface LabelsConfig {
recursive: string; recursive: string;
arrayOf: string; arrayOf: string;
webhook: string; webhook: string;
jsonrpc: string;
} }
export type LabelsConfigRaw = Partial<LabelsConfig>; export type LabelsConfigRaw = Partial<LabelsConfig>;
@ -24,6 +25,7 @@ const labels: LabelsConfig = {
recursive: 'Recursive', recursive: 'Recursive',
arrayOf: 'Array of ', arrayOf: 'Array of ',
webhook: 'Event', webhook: 'Event',
jsonrpc: 'Json-RPC',
}; };
export function setRedocLabels(_labels?: LabelsConfigRaw) { export function setRedocLabels(_labels?: LabelsConfigRaw) {

View File

@ -30,6 +30,7 @@ export type ExtendedOpenAPIOperation = {
pathParameters: Array<Referenced<OpenAPIParameter>>; pathParameters: Array<Referenced<OpenAPIParameter>>;
pathServers: Array<OpenAPIServer> | undefined; pathServers: Array<OpenAPIServer> | undefined;
isWebhook: boolean; isWebhook: boolean;
isJsonRpc: boolean;
} & OpenAPIOperation; } & OpenAPIOperation;
export type TagsInfoMap = Record<string, TagInfo>; export type TagsInfoMap = Record<string, TagInfo>;
@ -129,10 +130,10 @@ export class MenuBuilder {
} }
/** /**
* Returns array of OperationsGroup items for the tags of the group or for all tags * OperationsGroup .
* @param tagsMap tags info returned from `getTagsWithOperations` * @param tagsMap `getTagsWithOperations`
* @param parent parent item * @param parent
* @param group group which this tag belongs to. if not provided gets all tags * @param group . .
*/ */
static getTagsItems( static getTagsItems(
parser: OpenAPIParser, parser: OpenAPIParser,
@ -213,7 +214,7 @@ export class MenuBuilder {
} }
/** /**
* collects tags and maps each tag to list of operations belonging to this tag * operations .
*/ */
static getTagsWithOperations(spec: OpenAPISpec): TagsInfoMap { static getTagsWithOperations(spec: OpenAPISpec): TagsInfoMap {
const tags: TagsInfoMap = {}; const tags: TagsInfoMap = {};
@ -225,8 +226,11 @@ export class MenuBuilder {
if (spec['x-webhooks']) { if (spec['x-webhooks']) {
getTags(spec['x-webhooks'], true); getTags(spec['x-webhooks'], true);
} }
if (spec['jsonrpc']) {
getTags(spec['jsonrpc'], false, true);
}
function getTags(paths: OpenAPIPaths, isWebhook?: boolean) { function getTags(paths: OpenAPIPaths, isWebhook?: boolean, isJsonRpc?: boolean) {
for (const pathName of Object.keys(paths)) { for (const pathName of Object.keys(paths)) {
const path = paths[pathName]; const path = paths[pathName];
const operations = Object.keys(path).filter(isOperationName); const operations = Object.keys(path).filter(isOperationName);
@ -259,6 +263,7 @@ export class MenuBuilder {
pathParameters: path.parameters || [], pathParameters: path.parameters || [],
pathServers: path.servers, pathServers: path.servers,
isWebhook: !!isWebhook, isWebhook: !!isWebhook,
isJsonRpc: !!isJsonRpc,
}); });
} }
} }

View File

@ -7,7 +7,7 @@ import { SecuritySchemesModel } from './models/SecuritySchemes';
import { OpenAPIParser } from './OpenAPIParser'; import { OpenAPIParser } from './OpenAPIParser';
import { RedocNormalizedOptions } from './RedocNormalizedOptions'; import { RedocNormalizedOptions } from './RedocNormalizedOptions';
/** /**
* Store that contains all the specification related information in the form of tree * specification Store
*/ */
export class SpecStore { export class SpecStore {
parser: OpenAPIParser; parser: OpenAPIParser;

View File

@ -76,6 +76,7 @@ export class OperationModel implements IMenuItem {
extensions: Record<string, any>; extensions: Record<string, any>;
isCallback: boolean; isCallback: boolean;
isWebhook: boolean; isWebhook: boolean;
isJsonRpc: boolean;
constructor( constructor(
private parser: OpenAPIParser, private parser: OpenAPIParser,
@ -99,6 +100,7 @@ export class OperationModel implements IMenuItem {
this.path = operationSpec.pathName; this.path = operationSpec.pathName;
this.isCallback = isCallback; this.isCallback = isCallback;
this.isWebhook = !!operationSpec.isWebhook; this.isWebhook = !!operationSpec.isWebhook;
this.isJsonRpc = !!operationSpec.isJsonRpc;
this.name = getOperationSummary(operationSpec); this.name = getOperationSummary(operationSpec);

View File

@ -10,6 +10,7 @@ export interface OpenAPISpec {
tags?: OpenAPITag[]; tags?: OpenAPITag[];
externalDocs?: OpenAPIExternalDocumentation; externalDocs?: OpenAPIExternalDocumentation;
'x-webhooks'?: OpenAPIPaths; 'x-webhooks'?: OpenAPIPaths;
'jsonrpc'?: OpenAPIPaths;
} }
export interface OpenAPIInfo { export interface OpenAPIInfo {