mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 18:13:29 +00:00
Support expand-all options for OpenAPI (#4116)
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/openapi-parser": patch
|
||||||
|
"@gitbook/react-openapi": patch
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Support expand-all options for OpenAPI
|
||||||
@@ -50,6 +50,10 @@ async function OpenAPIOperationBody(props: BlockProps<AnyOpenAPIOperationsBlock>
|
|||||||
props,
|
props,
|
||||||
specUrl: publicURL,
|
specUrl: publicURL,
|
||||||
context: context.contentContext,
|
context: context.contentContext,
|
||||||
|
expandAllResponses:
|
||||||
|
data.operation['x-expandAllResponses'] ?? data['x-expandAllResponses'],
|
||||||
|
expandAllModelSections:
|
||||||
|
data.operation['x-expandAllModelSections'] ?? data['x-expandAllModelSections'],
|
||||||
})}
|
})}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -46,12 +46,13 @@ async function OpenAPISchemasBody(props: BlockProps<OpenAPISchemasBlock>) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseOpenAPISchemas
|
<BaseOpenAPISchemas
|
||||||
schemas={data.schemas}
|
data={data}
|
||||||
grouped={block.data.grouped}
|
grouped={block.data.grouped}
|
||||||
context={getOpenAPIContext({
|
context={getOpenAPIContext({
|
||||||
props,
|
props,
|
||||||
specUrl: publicURL,
|
specUrl: publicURL,
|
||||||
context: context.contentContext,
|
context: context.contentContext,
|
||||||
|
expandAllModelSections: data['x-expandAllModelSections'],
|
||||||
})}
|
})}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ async function OpenAPIWebhookBody(props: BlockProps<OpenAPIWebhookBlock>) {
|
|||||||
props,
|
props,
|
||||||
specUrl: publicURL,
|
specUrl: publicURL,
|
||||||
context: context.contentContext,
|
context: context.contentContext,
|
||||||
|
expandAllResponses:
|
||||||
|
data.operation['x-expandAllResponses'] ?? data['x-expandAllResponses'],
|
||||||
|
expandAllModelSections:
|
||||||
|
data.operation['x-expandAllModelSections'] ?? data['x-expandAllModelSections'],
|
||||||
})}
|
})}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ export function getOpenAPIContext(args: {
|
|||||||
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock | OpenAPIWebhookBlock>;
|
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock | OpenAPIWebhookBlock>;
|
||||||
specUrl: string | null;
|
specUrl: string | null;
|
||||||
context: GitBookAnyContext | undefined;
|
context: GitBookAnyContext | undefined;
|
||||||
|
expandAllResponses?: boolean;
|
||||||
|
expandAllModelSections?: boolean;
|
||||||
}): OpenAPIContextInput {
|
}): OpenAPIContextInput {
|
||||||
const { props, specUrl, context } = args;
|
const { props, specUrl, context, expandAllResponses, expandAllModelSections } = args;
|
||||||
const { block } = props;
|
const { block } = props;
|
||||||
|
|
||||||
const customizationLocale = context ? getSpaceLocale(context) : DEFAULT_LOCALE;
|
const customizationLocale = context ? getSpaceLocale(context) : DEFAULT_LOCALE;
|
||||||
@@ -91,7 +93,8 @@ export function getOpenAPIContext(args: {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
defaultInteractiveOpened: props.context.mode === 'print',
|
expandAllResponses: expandAllResponses || props.context.mode === 'print',
|
||||||
|
expandAllModelSections: expandAllModelSections || props.context.mode === 'print',
|
||||||
id: block.meta?.id,
|
id: block.meta?.id,
|
||||||
blockKey: block.key,
|
blockKey: block.key,
|
||||||
locale,
|
locale,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { OpenAPIParseError, type OpenAPISchema } from '@gitbook/openapi-parser';
|
import { OpenAPIParseError } from '@gitbook/openapi-parser';
|
||||||
import { resolveOpenAPISchemas } from '@gitbook/react-openapi';
|
import { type OpenAPISchemasData, resolveOpenAPISchemas } from '@gitbook/react-openapi';
|
||||||
import { fetchOpenAPIFilesystem } from './fetch';
|
import { fetchOpenAPIFilesystem } from './fetch';
|
||||||
import type {
|
import type {
|
||||||
OpenAPISchemasBlock,
|
OpenAPISchemasBlock,
|
||||||
@@ -7,9 +7,7 @@ import type {
|
|||||||
ResolveOpenAPIBlockResult,
|
ResolveOpenAPIBlockResult,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
type ResolveOpenAPISchemasBlockResult = ResolveOpenAPIBlockResult<{
|
type ResolveOpenAPISchemasBlockResult = ResolveOpenAPIBlockResult<OpenAPISchemasData>;
|
||||||
schemas: OpenAPISchema[];
|
|
||||||
}>;
|
|
||||||
|
|
||||||
const weakmap = new WeakMap<OpenAPISchemasBlock, Promise<ResolveOpenAPISchemasBlockResult>>();
|
const weakmap = new WeakMap<OpenAPISchemasBlock, Promise<ResolveOpenAPISchemasBlockResult>>();
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ export interface OpenAPICustomSpecProperties {
|
|||||||
*/
|
*/
|
||||||
'x-enable-proxy'?: boolean;
|
'x-enable-proxy'?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true`, all response sections will be expanded by default.
|
||||||
|
*/
|
||||||
|
'x-expandAllResponses'?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true`, all model/schema sections will be expanded by default.
|
||||||
|
*/
|
||||||
|
'x-expandAllModelSections'?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description in HTML format.
|
* Description in HTML format.
|
||||||
*/
|
*/
|
||||||
@@ -75,6 +85,16 @@ export interface OpenAPICustomOperationProperties {
|
|||||||
*/
|
*/
|
||||||
'x-enable-proxy'?: boolean;
|
'x-enable-proxy'?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true`, all response sections will be expanded by default.
|
||||||
|
*/
|
||||||
|
'x-expandAllResponses'?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true`, all model/schema sections will be expanded by default.
|
||||||
|
*/
|
||||||
|
'x-expandAllModelSections'?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stability of the operation.
|
* Stability of the operation.
|
||||||
* @enum 'experimental' | 'alpha' | 'beta'
|
* @enum 'experimental' | 'alpha' | 'beta'
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export function OpenAPIResponse(props: {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
icon={context.icons.plus}
|
icon={context.icons.plus}
|
||||||
|
defaultExpanded={context.expandAllModelSections}
|
||||||
label={(isExpanded) =>
|
label={(isExpanded) =>
|
||||||
tString(
|
tString(
|
||||||
context.translation,
|
context.translation,
|
||||||
|
|||||||
@@ -107,11 +107,19 @@ export function OpenAPIResponses(props: {
|
|||||||
|
|
||||||
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
||||||
|
|
||||||
|
const expandAll = context.expandAllResponses;
|
||||||
|
const expandedKeys = expandAll
|
||||||
|
? new Set(groups.map((g) => g.key))
|
||||||
|
: state.key
|
||||||
|
? new Set([state.key])
|
||||||
|
: new Set<string>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticSection header={t(context.translation, 'responses')} className="openapi-responses">
|
<StaticSection header={t(context.translation, 'responses')} className="openapi-responses">
|
||||||
<OpenAPIDisclosureGroup
|
<OpenAPIDisclosureGroup
|
||||||
icon={context.icons.chevronRight}
|
icon={context.icons.chevronRight}
|
||||||
expandedKeys={state.key ? new Set([state.key]) : new Set()}
|
allowsMultipleExpanded={expandAll}
|
||||||
|
expandedKeys={expandedKeys}
|
||||||
onExpandedChange={(keys) => {
|
onExpandedChange={(keys) => {
|
||||||
const key = keys.values().next().value ?? null;
|
const key = keys.values().next().value ?? null;
|
||||||
state.setKey(key);
|
state.setKey(key);
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ function OpenAPISchemaProperty(
|
|||||||
label={(isExpanded) =>
|
label={(isExpanded) =>
|
||||||
getDisclosureLabel({ schema: effectiveSchema, isExpanded, context })
|
getDisclosureLabel({ schema: effectiveSchema, isExpanded, context })
|
||||||
}
|
}
|
||||||
|
defaultExpanded={context.expandAllModelSections}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</OpenAPIDisclosure>
|
</OpenAPIDisclosure>
|
||||||
@@ -408,6 +409,7 @@ function OpenAPISchemaAlternative(props: {
|
|||||||
icon={context.icons.plus}
|
icon={context.icons.plus}
|
||||||
header={<OpenAPISchemaPresentation property={{ schema }} context={context} />}
|
header={<OpenAPISchemaPresentation property={{ schema }} context={context} />}
|
||||||
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
||||||
|
defaultExpanded={context.expandAllModelSections}
|
||||||
>
|
>
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={properties}
|
properties={properties}
|
||||||
|
|||||||
@@ -19,10 +19,16 @@ export interface OpenAPIClientContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force all sections to be opened by default.
|
* If `true`, all response sections will be expanded by default.
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
defaultInteractiveOpened?: boolean;
|
expandAllResponses?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If `true`, all model/schema sections will be expanded by default.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
expandAllModelSections?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The key of the block
|
* The key of the block
|
||||||
@@ -107,7 +113,8 @@ export function getOpenAPIClientContext(context: OpenAPIUniversalContext): OpenA
|
|||||||
return {
|
return {
|
||||||
translation: context.translation,
|
translation: context.translation,
|
||||||
icons: context.icons,
|
icons: context.icons,
|
||||||
defaultInteractiveOpened: context.defaultInteractiveOpened,
|
expandAllResponses: context.expandAllResponses,
|
||||||
|
expandAllModelSections: context.expandAllModelSections,
|
||||||
blockKey: context.blockKey,
|
blockKey: context.blockKey,
|
||||||
id: context.id,
|
id: context.id,
|
||||||
proxyUrl: '$$isClientContext$$' in context ? context.proxyUrl : undefined,
|
proxyUrl: '$$isClientContext$$' in context ? context.proxyUrl : undefined,
|
||||||
|
|||||||
@@ -83,6 +83,14 @@ export async function resolveOpenAPIOperation(
|
|||||||
: undefined,
|
: undefined,
|
||||||
'x-enable-proxy':
|
'x-enable-proxy':
|
||||||
typeof schema['x-enable-proxy'] === 'boolean' ? schema['x-enable-proxy'] : undefined,
|
typeof schema['x-enable-proxy'] === 'boolean' ? schema['x-enable-proxy'] : undefined,
|
||||||
|
'x-expandAllResponses':
|
||||||
|
typeof schema['x-expandAllResponses'] === 'boolean'
|
||||||
|
? schema['x-expandAllResponses']
|
||||||
|
: undefined,
|
||||||
|
'x-expandAllModelSections':
|
||||||
|
typeof schema['x-expandAllModelSections'] === 'boolean'
|
||||||
|
? schema['x-expandAllModelSections']
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ export async function resolveOpenAPIWebhook(
|
|||||||
operation,
|
operation,
|
||||||
method,
|
method,
|
||||||
name,
|
name,
|
||||||
|
'x-expandAllResponses':
|
||||||
|
typeof schema['x-expandAllResponses'] === 'boolean'
|
||||||
|
? schema['x-expandAllResponses']
|
||||||
|
: undefined,
|
||||||
|
'x-expandAllModelSections':
|
||||||
|
typeof schema['x-expandAllModelSections'] === 'boolean'
|
||||||
|
? schema['x-expandAllModelSections']
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function OpenAPISchemaItem(props: {
|
|||||||
icon={context.icons.plus}
|
icon={context.icons.plus}
|
||||||
header={name}
|
header={name}
|
||||||
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
||||||
|
defaultExpanded={context.expandAllModelSections}
|
||||||
>
|
>
|
||||||
<Section className="openapi-section-schemas">
|
<Section className="openapi-section-schemas">
|
||||||
<SectionBody>
|
<SectionBody>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { OpenAPISchema } from '@gitbook/openapi-parser';
|
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import { OpenAPIExample } from '../OpenAPIExample';
|
import { OpenAPIExample } from '../OpenAPIExample';
|
||||||
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
||||||
@@ -11,20 +10,22 @@ import {
|
|||||||
import { t } from '../translate';
|
import { t } from '../translate';
|
||||||
import { getExampleFromSchema } from '../util/example';
|
import { getExampleFromSchema } from '../util/example';
|
||||||
import { OpenAPISchemaItem } from './OpenAPISchemaItem';
|
import { OpenAPISchemaItem } from './OpenAPISchemaItem';
|
||||||
|
import type { OpenAPISchemasData } from './resolveOpenAPISchemas';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenAPI Schemas component.
|
* OpenAPI Schemas component.
|
||||||
*/
|
*/
|
||||||
export function OpenAPISchemas(props: {
|
export function OpenAPISchemas(props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
schemas: OpenAPISchema[];
|
data: OpenAPISchemasData;
|
||||||
context: OpenAPIContextInput;
|
context: OpenAPIContextInput;
|
||||||
/**
|
/**
|
||||||
* Whether to show the schema directly if there is only one.
|
* Whether to show the schema directly if there is only one.
|
||||||
*/
|
*/
|
||||||
grouped?: boolean;
|
grouped?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { schemas, context: contextInput, grouped, className } = props;
|
const { data, context: contextInput, grouped, className } = props;
|
||||||
|
const { schemas } = data;
|
||||||
|
|
||||||
const firstSchema = schemas[0];
|
const firstSchema = schemas[0];
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
import type { Filesystem, OpenAPISchema, OpenAPIV3xDocument } from '@gitbook/openapi-parser';
|
import type {
|
||||||
|
Filesystem,
|
||||||
|
OpenAPICustomSpecProperties,
|
||||||
|
OpenAPISchema,
|
||||||
|
OpenAPIV3xDocument,
|
||||||
|
} from '@gitbook/openapi-parser';
|
||||||
import { filterSelectedOpenAPISchemas } from '@gitbook/openapi-parser';
|
import { filterSelectedOpenAPISchemas } from '@gitbook/openapi-parser';
|
||||||
import { dereferenceFilesystem } from '../dereference';
|
import { dereferenceFilesystem } from '../dereference';
|
||||||
|
|
||||||
|
export type OpenAPISchemasData = Pick<OpenAPICustomSpecProperties, 'x-expandAllModelSections'> & {
|
||||||
|
schemas: OpenAPISchema[];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an OpenAPI schemas from a file and compile it to a more usable format.
|
* Resolve an OpenAPI schemas from a file and compile it to a more usable format.
|
||||||
* Schemas are extracted from the OpenAPI components.schemas
|
* Schemas are extracted from the OpenAPI components.schemas
|
||||||
@@ -11,9 +20,7 @@ export async function resolveOpenAPISchemas(
|
|||||||
options: {
|
options: {
|
||||||
schemas: string[];
|
schemas: string[];
|
||||||
}
|
}
|
||||||
): Promise<{
|
): Promise<OpenAPISchemasData | null> {
|
||||||
schemas: OpenAPISchema[];
|
|
||||||
} | null> {
|
|
||||||
const { schemas: selectedSchemas } = options;
|
const { schemas: selectedSchemas } = options;
|
||||||
|
|
||||||
const schema = await dereferenceFilesystem(filesystem);
|
const schema = await dereferenceFilesystem(filesystem);
|
||||||
@@ -24,5 +31,11 @@ export async function resolveOpenAPISchemas(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { schemas };
|
return {
|
||||||
|
schemas,
|
||||||
|
'x-expandAllModelSections':
|
||||||
|
typeof schema['x-expandAllModelSections'] === 'boolean'
|
||||||
|
? schema['x-expandAllModelSections']
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user