mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 15:45:13 +00:00
Support GitBook blocks in OpenAPI operation description (#2868)
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@gitbook/openapi-parser': patch
|
||||||
|
'@gitbook/react-openapi': patch
|
||||||
|
'gitbook': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Render GitBook blocks in OpenAPI operation description
|
||||||
@@ -244,8 +244,8 @@ async function PDFPageDocument(props: {
|
|||||||
{document ? (
|
{document ? (
|
||||||
<DocumentView
|
<DocumentView
|
||||||
document={document}
|
document={document}
|
||||||
style={'mt-6 space-y-6'}
|
style="mt-6 space-y-6"
|
||||||
blockStyle={['max-w-full']}
|
blockStyle="max-w-full"
|
||||||
context={{
|
context={{
|
||||||
mode: 'print',
|
mode: 'print',
|
||||||
content: {
|
content: {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DocumentBlockOpenAPI } from '@gitbook/api';
|
import { DocumentBlockOpenAPI, JSONDocument } from '@gitbook/api';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import { OpenAPIOperation } from '@gitbook/react-openapi';
|
import { OpenAPIOperation } from '@gitbook/react-openapi';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@@ -8,6 +8,7 @@ import { tcls } from '@/lib/tailwind';
|
|||||||
|
|
||||||
import { BlockProps } from '../Block';
|
import { BlockProps } from '../Block';
|
||||||
import { PlainCodeBlock } from '../CodeBlock';
|
import { PlainCodeBlock } from '../CodeBlock';
|
||||||
|
import { DocumentView } from '../DocumentView';
|
||||||
import { Heading } from '../Heading';
|
import { Heading } from '../Heading';
|
||||||
|
|
||||||
import './style.css';
|
import './style.css';
|
||||||
@@ -57,7 +58,15 @@ async function OpenAPIBody(props: BlockProps<DocumentBlockOpenAPI>) {
|
|||||||
chevronRight: <Icon icon="chevron-right" />,
|
chevronRight: <Icon icon="chevron-right" />,
|
||||||
plus: <Icon icon="plus" />,
|
plus: <Icon icon="plus" />,
|
||||||
},
|
},
|
||||||
CodeBlock: PlainCodeBlock,
|
renderCodeBlock: (codeProps) => <PlainCodeBlock {...codeProps} />,
|
||||||
|
renderDocument: (documentProps) => (
|
||||||
|
<DocumentView
|
||||||
|
document={documentProps.document as JSONDocument}
|
||||||
|
context={props.context}
|
||||||
|
style="space-y-6"
|
||||||
|
blockStyle="max-w-full"
|
||||||
|
/>
|
||||||
|
),
|
||||||
renderHeading: (headingProps) => (
|
renderHeading: (headingProps) => (
|
||||||
<Heading
|
<Heading
|
||||||
document={props.document}
|
document={props.document}
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ export interface OpenAPICustomOperationProperties {
|
|||||||
* Description in HTML format.
|
* Description in HTML format.
|
||||||
*/
|
*/
|
||||||
'x-gitbook-description-html'?: string;
|
'x-gitbook-description-html'?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description in Document format.
|
||||||
|
*/
|
||||||
|
'x-gitbook-description-document'?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -72,7 +72,10 @@ export function OpenAPICodeSample(props: {
|
|||||||
const autoCodeSamples = codeSampleGenerators.map((generator) => ({
|
const autoCodeSamples = codeSampleGenerators.map((generator) => ({
|
||||||
key: `default-${generator.id}`,
|
key: `default-${generator.id}`,
|
||||||
label: generator.label,
|
label: generator.label,
|
||||||
body: <context.CodeBlock code={generator.generate(input)} syntax={generator.syntax} />,
|
body: context.renderCodeBlock({
|
||||||
|
code: generator.generate(input),
|
||||||
|
syntax: generator.syntax,
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Use custom samples if defined
|
// Use custom samples if defined
|
||||||
@@ -95,7 +98,10 @@ export function OpenAPICodeSample(props: {
|
|||||||
.map((sample) => ({
|
.map((sample) => ({
|
||||||
key: `redocly-${sample.lang}`,
|
key: `redocly-${sample.lang}`,
|
||||||
label: sample.label,
|
label: sample.label,
|
||||||
body: <context.CodeBlock code={sample.source} syntax={sample.lang} />,
|
body: context.renderCodeBlock({
|
||||||
|
code: sample.source,
|
||||||
|
syntax: sample.lang,
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { OpenAPISpec } from './OpenAPISpec';
|
|||||||
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
|
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types';
|
||||||
import { OpenAPIPath } from './OpenAPIPath';
|
import { OpenAPIPath } from './OpenAPIPath';
|
||||||
import { resolveDescription } from './utils';
|
import { resolveDescription } from './utils';
|
||||||
|
import { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an interactive OpenAPI operation.
|
* Display an interactive OpenAPI operation.
|
||||||
@@ -25,8 +26,6 @@ export function OpenAPIOperation(props: {
|
|||||||
blockKey: context.blockKey,
|
blockKey: context.blockKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
const description = resolveDescription(operation);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('openapi-operation', className)}>
|
<div className={clsx('openapi-operation', className)}>
|
||||||
<div className="openapi-summary" id={operation.summary ? undefined : context.id}>
|
<div className="openapi-summary" id={operation.summary ? undefined : context.id}>
|
||||||
@@ -49,11 +48,7 @@ export function OpenAPIOperation(props: {
|
|||||||
{`.`}
|
{`.`}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{description ? (
|
<OpenAPIOperationDescription operation={operation} context={context} />
|
||||||
<div className="openapi-intro">
|
|
||||||
<Markdown className="openapi-description" source={description} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<OpenAPIPath data={data} context={context} />
|
<OpenAPIPath data={data} context={context} />
|
||||||
<OpenAPISpec data={data} context={clientContext} />
|
<OpenAPISpec data={data} context={clientContext} />
|
||||||
</div>
|
</div>
|
||||||
@@ -67,3 +62,30 @@ export function OpenAPIOperation(props: {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function OpenAPIOperationDescription(props: {
|
||||||
|
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
||||||
|
context: OpenAPIContextProps;
|
||||||
|
}) {
|
||||||
|
const { operation } = props;
|
||||||
|
if (operation['x-gitbook-description-document']) {
|
||||||
|
return (
|
||||||
|
<div className="openapi-intro">
|
||||||
|
{props.context.renderDocument({
|
||||||
|
document: operation['x-gitbook-description-document'],
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const description = resolveDescription(operation);
|
||||||
|
if (!description) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="openapi-intro">
|
||||||
|
<Markdown className="openapi-description" source={description} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ function OpenAPIExample(props: {
|
|||||||
return <OpenAPIEmptyResponseExample />;
|
return <OpenAPIEmptyResponseExample />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <context.CodeBlock code={code} syntax={syntax} />;
|
return context.renderCodeBlock({ code, syntax });
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
|
function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean }): string | null {
|
||||||
|
|||||||
@@ -5,8 +5,18 @@ import type {
|
|||||||
} from '@gitbook/openapi-parser';
|
} from '@gitbook/openapi-parser';
|
||||||
|
|
||||||
export interface OpenAPIContextProps extends OpenAPIClientContext {
|
export interface OpenAPIContextProps extends OpenAPIClientContext {
|
||||||
CodeBlock: React.ComponentType<{ code: string; syntax: string }>;
|
/**
|
||||||
|
* Render a code block.
|
||||||
|
*/
|
||||||
|
renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
|
||||||
|
/**
|
||||||
|
* Render the heading of the operation.
|
||||||
|
*/
|
||||||
renderHeading: (props: { deprecated: boolean; title: string }) => React.ReactNode;
|
renderHeading: (props: { deprecated: boolean; title: string }) => React.ReactNode;
|
||||||
|
/**
|
||||||
|
* Render the document of the operation.
|
||||||
|
*/
|
||||||
|
renderDocument: (props: { document: object }) => React.ReactNode;
|
||||||
|
|
||||||
/** Spec url for the Scalar Api Client */
|
/** Spec url for the Scalar Api Client */
|
||||||
specUrl: string;
|
specUrl: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user