Support for x-enumDescriptions and x-gitbook-enum (#3066)

This commit is contained in:
Nolann B.
2025-03-31 12:18:57 +02:00
committed by GitHub
parent 6f71da88d8
commit 813b2af06b
5 changed files with 99 additions and 18 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@gitbook/openapi-parser': patch
'@gitbook/react-openapi': patch
'gitbook': patch
---
Support for x-enumDescriptions and x-gitbook-enum
@@ -244,7 +244,11 @@
/* Schema Enum */
.openapi-schema-enum {
@apply flex flex-row text-sm leading-relaxed flex-wrap text-tint;
@apply flex flex-row text-sm leading-relaxed gap-2 flex-wrap text-tint;
}
.openapi-schema-enum-list {
@apply flex flex-row gap-1.5 items-center;
}
.openapi-schema-enum-value {
@@ -693,3 +697,7 @@
opacity: 0;
}
}
.openapi-copy-button {
@apply hover:brightness-95;
}
+15
View File
@@ -47,6 +47,21 @@ export interface OpenAPICustomOperationProperties {
* Description in Document format.
*/
'x-gitbook-description-document'?: object;
/**
* Enums with name and description
*/
'x-enumDescriptions'?: object;
/**
* Enums with name and description
*/
'x-gitbook-enum'?: {
[key: string]: {
description?: string;
name?: string;
};
};
}
/**
@@ -6,10 +6,16 @@ import { Button, type ButtonProps, Tooltip, TooltipTrigger } from 'react-aria-co
export function OpenAPICopyButton(
props: ButtonProps & {
value: string;
children: React.ReactNode;
label?: string;
/**
* Whether to show a tooltip.
* @default true
*/
withTooltip?: boolean;
}
) {
const { value } = props;
const { children, onPress, className } = props;
const { value, label, children, onPress, className, withTooltip = true } = props;
const [copied, setCopied] = useState(false);
const [isOpen, setIsOpen] = useState(false);
@@ -21,12 +27,19 @@ export function OpenAPICopyButton(
setTimeout(() => {
setCopied(false);
setIsOpen(false);
}, 2000);
});
};
return (
<TooltipTrigger isOpen={isOpen} onOpenChange={setIsOpen} closeDelay={200} delay={200}>
<TooltipTrigger
isOpen={isOpen}
onOpenChange={setIsOpen}
isDisabled={!withTooltip}
closeDelay={200}
delay={200}
>
<Button
type="button"
preventFocusOnPress
@@ -47,7 +60,7 @@ export function OpenAPICopyButton(
offset={4}
className="openapi-tooltip"
>
{copied ? 'Copied' : 'Copy to clipboard'}{' '}
{copied ? 'Copied' : label || 'Copy to clipboard'}
</Tooltip>
</TooltipTrigger>
);
+51 -13
View File
@@ -2,11 +2,12 @@
// This component does not use any client feature but we don't want to
// render it server-side because it has recursion.
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
import { useId } from 'react';
import clsx from 'clsx';
import { Markdown } from './Markdown';
import { OpenAPICopyButton } from './OpenAPICopyButton';
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
import { OpenAPISchemaName } from './OpenAPISchemaName';
import { retrocycle } from './decycle';
@@ -236,20 +237,59 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
/**
* Render the enum value for a schema.
*/
function OpenAPISchemaEnum(props: { enumValues: any[] }) {
const { enumValues } = props;
function OpenAPISchemaEnum(props: {
schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
}) {
const { schema } = props;
const enumValues = (() => {
// Render x-gitbook-enum first, as it has a different format
if (schema['x-gitbook-enum']) {
return Object.entries(schema['x-gitbook-enum']).map(([name, { description }]) => {
return {
value: name,
description,
};
});
}
if (schema['x-enumDescriptions']) {
return Object.entries(schema['x-enumDescriptions']).map(([value, description]) => {
return {
value,
description,
};
});
}
return schema.enum?.map((value) => {
return {
value,
description: undefined,
};
});
})();
if (!enumValues?.length) {
return null;
}
return (
<div className="openapi-schema-enum">
<span>
Options:{' '}
{enumValues.map((value, index) => (
<span>Available options:</span>
<div className="openapi-schema-enum-list">
{enumValues.map((item, index) => (
<span key={index} className="openapi-schema-enum-value">
<code>{`${value}`}</code>
{index < enumValues.length - 1 ? ', ' : ''}
<OpenAPICopyButton
value={item.value}
label={item.description}
withTooltip={!!item.description}
>
<code>{`${item.value}`}</code>
</OpenAPICopyButton>
</span>
))}
</span>
</div>
</div>
);
}
@@ -294,9 +334,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
Pattern: <code>{schema.pattern}</code>
</div>
) : null}
{schema.enum && schema.enum.length > 0 ? (
<OpenAPISchemaEnum enumValues={schema.enum} />
) : null}
<OpenAPISchemaEnum schema={schema} />
</div>
);
}
@@ -421,7 +459,7 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
// Otherwise try to infer a nice title
let type = 'any';
if (schema.enum) {
if (schema.enum || schema['x-enumDescriptions'] || schema['x-gitbook-enum']) {
type = `${schema.type} · enum`;
// check array AND schema.items as this is sometimes null despite what the type indicates
} else if (schema.type === 'array' && !!schema.items) {