Compare commits

..

7 Commits

Author SHA1 Message Date
Samy Pessé c0b339e406 Version Packages (#3075)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-02 13:36:04 +02:00
Nolann B. da485f5144 Fix read-only in generateSchemaExample (#3069) 2025-04-02 13:03:51 +02:00
Nolann B. 139a8050a5 Fix OpenAPI enum display (#3077) 2025-04-02 10:15:19 +02:00
Nolann B. da7b369ffd Fix missing headers in OpenAPIResponses (#3074) 2025-04-01 21:57:36 +02:00
Samy Pessé 432da64919 Version Packages (#3073)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-01 18:13:52 +02:00
Nolann B. 7d0b422200 Handle grouped OpenAPISchemas (#3071) 2025-04-01 17:24:43 +02:00
Zeno Kapitein fb90eb0acc Limit tinted background on bold theme to sites with filled sidebar (#3072) 2025-04-01 16:43:08 +02:00
25 changed files with 233 additions and 97 deletions
+6
View File
@@ -1,5 +1,11 @@
# @gitbook/colors # @gitbook/colors
## 0.3.1
### Patch Changes
- fb90eb0: Reduce chroma of first color scale step
## 0.3.0 ## 0.3.0
### Minor Changes ### Minor Changes
+1 -1
View File
@@ -8,7 +8,7 @@
"default": "./dist/index.js" "default": "./dist/index.js"
} }
}, },
"version": "0.3.0", "version": "0.3.1",
"devDependencies": { "devDependencies": {
"typescript": "^5.5.3" "typescript": "^5.5.3"
}, },
+1 -1
View File
@@ -220,7 +220,7 @@ export function colorScale(
continue; continue;
} }
const chromaRatio = index < 8 ? (index + 1) * 0.05 : 1; const chromaRatio = index < 8 ? index * 0.05 : 1;
const shade = { const shade = {
L: targetL, // Blend lightness L: targetL, // Blend lightness
+22
View File
@@ -1,5 +1,27 @@
# gitbook # gitbook
## 0.9.2
### Patch Changes
- da7b369: Fix missing headers in OpenAPIResponses
- 139a805: Fix OpenAPI enum display
- Updated dependencies [da7b369]
- Updated dependencies [da485f5]
- Updated dependencies [139a805]
- @gitbook/react-openapi@1.1.9
## 0.9.1
### Patch Changes
- fb90eb0: Limit tinted background on bold theme to sites with filled sidebar
- 7d0b422: Handle grouped OpenAPISchemas
- Updated dependencies [7d0b422]
- Updated dependencies [fb90eb0]
- @gitbook/react-openapi@1.1.8
- @gitbook/colors@0.3.1
## 0.9.0 ## 0.9.0
### Minor Changes ### Minor Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "gitbook", "name": "gitbook",
"version": "0.9.0", "version": "0.9.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "env-cmd --silent -f ../../.env.local next dev", "dev": "env-cmd --silent -f ../../.env.local next dev",
@@ -104,7 +104,7 @@ const HINT_STYLES: {
'[&_.can-override-text]:text-neutral-strong', '[&_.can-override-text]:text-neutral-strong',
], ],
container: container:
'bg-info border-info theme-muted-tint:bg-info-solid/2 theme-bold-tint:bg-info-solid/2', 'bg-info border-info theme-muted-tint:bg-info-solid/2 [html.sidebar-filled.theme-bold.tint_&]:bg-info-solid/2',
containerWithHeader: 'border-info-solid bg-info-subtle', containerWithHeader: 'border-info-solid bg-info-subtle',
}, },
warning: { warning: {
@@ -50,6 +50,7 @@ async function OpenAPISchemasBody(props: BlockProps<OpenAPISchemasBlock>) {
return ( return (
<BaseOpenAPISchemas <BaseOpenAPISchemas
data={data} data={data}
grouped={block.data.grouped}
context={{ context={{
specUrl, specUrl,
icons: { icons: {
@@ -265,15 +265,11 @@
/* Schema Enum */ /* Schema Enum */
.openapi-schema-enum { .openapi-schema-enum {
@apply flex flex-row text-sm leading-relaxed gap-2 flex-wrap text-tint; @apply text-sm leading-relaxed max-w-full text-tint;
}
.openapi-schema-enum-list {
@apply flex flex-row gap-1.5 items-center;
} }
.openapi-schema-enum-value { .openapi-schema-enum-value {
@apply text-sm; @apply text-sm mr-1.5;
} }
.openapi-schema-enum-value:first-child { .openapi-schema-enum-value:first-child {
@@ -38,7 +38,7 @@ export function Header(props: { context: GitBookSiteContext; withTopHeader?: boo
'bg-tint-base/9', 'bg-tint-base/9',
'theme-muted:bg-tint-subtle/9', 'theme-muted:bg-tint-subtle/9',
'theme-bold-tint:bg-tint-subtle/9', '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle/9',
'theme-gradient:bg-gradient-primary', 'theme-gradient:bg-gradient-primary',
'theme-gradient-tint:bg-gradient-tint', 'theme-gradient-tint:bg-gradient-tint',
'contrast-more:bg-tint-base', 'contrast-more:bg-tint-base',
@@ -228,7 +228,7 @@ export function PageAside(props: {
) : null} ) : null}
<div <div
className={tcls( className={tcls(
'sticky bottom-0 z-10 mt-auto flex flex-col bg-tint-base theme-bold-tint:bg-tint-subtle theme-gradient-tint:bg-gradient-tint theme-gradient:bg-gradient-primary theme-muted:bg-tint-subtle pb-4 page-api-block:xl:max-2xl:hidden page-api-block:xl:max-2xl:pb-0 page-api-block:xl:max-2xl:group-hover/aside:flex', 'sticky bottom-0 z-10 mt-auto flex flex-col bg-tint-base theme-gradient-tint:bg-gradient-tint theme-gradient:bg-gradient-primary theme-muted:bg-tint-subtle pb-4 page-api-block:xl:max-2xl:hidden page-api-block:xl:max-2xl:pb-0 page-api-block:xl:max-2xl:group-hover/aside:flex [html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
'page-api-block:xl:max-2xl:bg-transparent' 'page-api-block:xl:max-2xl:bg-transparent'
)} )}
> >
@@ -111,7 +111,7 @@ export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
'hover:bg-primary-hover', 'hover:bg-primary-hover',
'theme-muted:hover:bg-primary-active', 'theme-muted:hover:bg-primary-active',
'theme-bold-tint:hover:bg-primary-active', '[html.sidebar-filled.theme-bold.tint_&]:hover:bg-primary-active',
'theme-gradient:hover:bg-primary-active', 'theme-gradient:hover:bg-primary-active',
'tint:font-semibold', 'tint:font-semibold',
@@ -153,9 +153,9 @@ export async function CustomizationRootLayout(props: {
</head> </head>
<body <body
className={tcls( className={tcls(
'[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
'bg-tint-base', 'bg-tint-base',
'theme-muted:bg-tint-subtle', 'theme-muted:bg-tint-subtle',
'theme-bold-tint:bg-tint-subtle',
'theme-gradient:bg-gradient-primary', 'theme-gradient:bg-gradient-primary',
'theme-gradient-tint:bg-gradient-tint' 'theme-gradient-tint:bg-gradient-tint'
@@ -32,7 +32,7 @@ export function SiteSectionList(props: { sections: ClientSiteSections; className
<nav <nav
aria-label="Sections" aria-label="Sections"
className={tcls( className={tcls(
'-mx-5 before:contents[] relative border-tint-subtle border-b from-transparent sidebar-filled:to-tint-subtle theme-bold-tint:to-tint-subtle theme-muted:to-tint-subtle to-tint-base text-sm text-tint before:pointer-events-none before:absolute before:right-2 before:bottom-0 before:left-0 before:h-12 before:bg-gradient-to-b [html.sidebar-filled.theme-bold.tint_&]:to-tint-base [html.sidebar-filled.theme-muted_&]:to-tint-base', '-mx-5 before:contents[] relative border-tint-subtle border-b from-transparent sidebar-filled:to-tint-subtle theme-muted:to-tint-subtle to-tint-base text-sm text-tint before:pointer-events-none before:absolute before:right-2 before:bottom-0 before:left-0 before:h-12 before:bg-gradient-to-b [html.sidebar-filled.theme-bold.tint_&]:to-tint-base [html.sidebar-filled.theme-bold.tint_&]:to-tint-subtle [html.sidebar-filled.theme-muted_&]:to-tint-base',
className className
)} )}
> >
@@ -40,7 +40,7 @@ export function PageGroupItem(props: {
'bg-tint-base', 'bg-tint-base',
'sidebar-filled:bg-tint-subtle', 'sidebar-filled:bg-tint-subtle',
'theme-muted:bg-tint-subtle', 'theme-muted:bg-tint-subtle',
'theme-bold-tint:bg-tint-subtle', '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
'[html.sidebar-filled.theme-muted_&]:bg-tint-base', '[html.sidebar-filled.theme-muted_&]:bg-tint-base',
'[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base', '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base',
'[html.sidebar-default.theme-gradient_&]:bg-gradient-primary', '[html.sidebar-default.theme-gradient_&]:bg-gradient-primary',
@@ -75,7 +75,7 @@ export function TableOfContents(props: {
'sidebar-filled:bg-tint-subtle', 'sidebar-filled:bg-tint-subtle',
'theme-muted:bg-tint-subtle', 'theme-muted:bg-tint-subtle',
'theme-bold-tint:bg-tint-subtle', '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
'[html.sidebar-filled.theme-muted_&]:bg-tint-base', '[html.sidebar-filled.theme-muted_&]:bg-tint-base',
'[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base', '[html.sidebar-filled.theme-bold.tint_&]:bg-tint-base',
'page-no-toc:!bg-transparent', 'page-no-toc:!bg-transparent',
@@ -52,7 +52,7 @@ export function Trademark(props: {
'before:to-tint-base', 'before:to-tint-base',
'sidebar-filled:before:to-tint-subtle', 'sidebar-filled:before:to-tint-subtle',
'theme-muted:before:to-tint-subtle', 'theme-muted:before:to-tint-subtle',
'theme-bold-tint:before:to-tint-subtle', '[html.sidebar-filled.theme-bold.tint_&]:before:to-tint-subtle',
'[html.sidebar-filled.theme-muted_&]:before:to-tint-base', '[html.sidebar-filled.theme-muted_&]:before:to-tint-base',
'[html.sidebar-filled.theme-bold.tint_&]:before:to-tint-base', '[html.sidebar-filled.theme-bold.tint_&]:before:to-tint-base',
'page-no-toc:before:!to-transparent' 'page-no-toc:before:!to-transparent'
@@ -79,7 +79,7 @@ function ThemeButton(props: {
active && [ active && [
'bg-primary', 'bg-primary',
'theme-muted:bg-primary-hover', 'theme-muted:bg-primary-hover',
'theme-bold-tint:bg-primary-hover', '[html.sidebar-filled.theme-bold.tint_&]:bg-primary-hover',
'hover:bg-primary', 'hover:bg-primary',
'text-primary-strong', 'text-primary-strong',
'contrast-more:text-primary-strong', 'contrast-more:text-primary-strong',
+14
View File
@@ -1,5 +1,19 @@
# @gitbook/react-openapi # @gitbook/react-openapi
## 1.1.9
### Patch Changes
- da7b369: Fix missing headers in OpenAPIResponses
- da485f5: Fix read-only in generateSchemaExample
- 139a805: Fix OpenAPI enum display
## 1.1.8
### Patch Changes
- 7d0b422: Handle grouped OpenAPISchemas
## 1.1.7 ## 1.1.7
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -8,7 +8,7 @@
"default": "./dist/index.js" "default": "./dist/index.js"
} }
}, },
"version": "1.1.7", "version": "1.1.9",
"sideEffects": false, "sideEffects": false,
"dependencies": { "dependencies": {
"@gitbook/openapi-parser": "workspace:*", "@gitbook/openapi-parser": "workspace:*",
@@ -36,13 +36,15 @@ export function OpenAPIResponse(props: {
/> />
</OpenAPIDisclosure> </OpenAPIDisclosure>
) : null} ) : null}
{mediaType.schema && (
<div className="openapi-responsebody"> <div className="openapi-responsebody">
<OpenAPISchemaProperties <OpenAPISchemaProperties
id={`response-${context.blockKey}`} id={`response-${context.blockKey}`}
properties={mediaType.schema ? [{ schema: mediaType.schema }] : []} properties={[{ schema: mediaType.schema }]}
context={context} context={context}
/> />
</div> </div>
)}
</div> </div>
); );
} }
@@ -268,6 +268,7 @@ function getExamplesFromMediaTypeObject(args: {
value: { value: {
[root]: generateSchemaExample(mediaTypeObject.schema, { [root]: generateSchemaExample(mediaTypeObject.schema, {
xml: mediaType === 'application/xml', xml: mediaType === 'application/xml',
mode: 'read',
}), }),
}, },
}, },
@@ -277,7 +278,11 @@ function getExamplesFromMediaTypeObject(args: {
return [ return [
{ {
key: 'default', key: 'default',
example: { value: generateSchemaExample(mediaTypeObject.schema) }, example: {
value: generateSchemaExample(mediaTypeObject.schema, {
mode: 'read',
}),
},
}, },
]; ];
} }
+37 -12
View File
@@ -21,7 +21,42 @@ export function OpenAPIResponses(props: {
icon={context.icons.chevronRight} icon={context.icons.chevronRight}
groups={Object.entries(responses).map( groups={Object.entries(responses).map(
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => { ([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
const content = Object.entries(response.content ?? {}); const tabs = (() => {
// If there is no content, but there are headers, we need to show the headers
if (
(!response.content || !Object.keys(response.content).length) &&
response.headers &&
Object.keys(response.headers).length
) {
return [
{
id: 'default',
body: (
<OpenAPIResponse
response={response}
mediaType={{}}
context={context}
/>
),
},
];
}
return Object.entries(response.content ?? {}).map(
([contentType, mediaType]) => ({
id: contentType,
label: contentType,
body: (
<OpenAPIResponse
response={response}
mediaType={mediaType}
context={context}
/>
),
})
);
})();
const description = response.description; const description = response.description;
return { return {
@@ -39,17 +74,7 @@ export function OpenAPIResponses(props: {
) : null} ) : null}
</div> </div>
), ),
tabs: content.map(([contentType, mediaType]) => ({ tabs,
id: contentType,
label: contentType,
body: (
<OpenAPIResponse
response={response}
mediaType={mediaType}
context={context}
/>
),
})),
}; };
} }
)} )}
+3 -5
View File
@@ -275,9 +275,8 @@ function OpenAPISchemaEnum(props: {
} }
return ( return (
<div className="openapi-schema-enum"> <span className="openapi-schema-enum">
<span>Available options:</span> Available options:{' '}
<div className="openapi-schema-enum-list">
{enumValues.map((item, index) => ( {enumValues.map((item, index) => (
<span key={index} className="openapi-schema-enum-value"> <span key={index} className="openapi-schema-enum-value">
<OpenAPICopyButton <OpenAPICopyButton
@@ -289,8 +288,7 @@ function OpenAPISchemaEnum(props: {
</OpenAPICopyButton> </OpenAPICopyButton>
</span> </span>
))} ))}
</div> </span>
</div>
); );
} }
@@ -16,14 +16,10 @@ export function generateSchemaExample(
schema: OpenAPIV3.SchemaObject, schema: OpenAPIV3.SchemaObject,
options?: GenerateSchemaExampleOptions options?: GenerateSchemaExampleOptions
): JSONValue | undefined { ): JSONValue | undefined {
return getExampleFromSchema( return getExampleFromSchema(schema, {
schema,
{
emptyString: 'text', emptyString: 'text',
...options, ...options,
}, });
3 // Max depth for circular references
);
} }
/** /**
@@ -103,21 +99,6 @@ function guessFromFormat(schema: Record<string, any>, fallback = '') {
return genericExampleValues[schema.format] ?? fallback; return genericExampleValues[schema.format] ?? fallback;
} }
/** Map of all the results */
const resultCache = new WeakMap<Record<string, any>, any>();
/** Store result in the cache, and return the result */
function cache(schema: Record<string, any>, result: unknown) {
// Avoid unnecessary WeakMap operations for primitive values
if (typeof result !== 'object' || result === null) {
return result;
}
resultCache.set(schema, result);
return result;
}
/** /**
* This function takes an OpenAPI schema and generates an example from it * This function takes an OpenAPI schema and generates an example from it
* Forked from : https://github.com/scalar/scalar/blob/main/packages/oas-utils/src/spec-getters/getExampleFromSchema.ts * Forked from : https://github.com/scalar/scalar/blob/main/packages/oas-utils/src/spec-getters/getExampleFromSchema.ts
@@ -152,8 +133,20 @@ const getExampleFromSchema = (
}, },
level = 0, level = 0,
parentSchema?: Record<string, any>, parentSchema?: Record<string, any>,
name?: string name?: string,
resultCache = new WeakMap<Record<string, any>, any>()
): any => { ): any => {
// Store result in the cache, and return the result
function cache(schema: Record<string, any>, result: unknown) {
// Avoid unnecessary WeakMap operations for primitive values
if (typeof result !== 'object' || result === null) {
return result;
}
resultCache.set(schema, result);
return result;
}
// Check if the result is already cached // Check if the result is already cached
if (resultCache.has(schema)) { if (resultCache.has(schema)) {
return resultCache.get(schema); return resultCache.get(schema);
@@ -245,7 +238,8 @@ const getExampleFromSchema = (
options, options,
level + 1, level + 1,
schema, schema,
propertyName propertyName,
resultCache
); );
if (typeof response[propertyXmlTagName ?? propertyName] === 'undefined') { if (typeof response[propertyXmlTagName ?? propertyName] === 'undefined') {
@@ -269,7 +263,8 @@ const getExampleFromSchema = (
options, options,
level + 1, level + 1,
schema, schema,
exampleKey exampleKey,
resultCache
); );
} }
} }
@@ -290,21 +285,51 @@ const getExampleFromSchema = (
response.ANY_ADDITIONAL_PROPERTY = getExampleFromSchema( response.ANY_ADDITIONAL_PROPERTY = getExampleFromSchema(
schema.additionalProperties, schema.additionalProperties,
options, options,
level + 1 level + 1,
undefined,
undefined,
resultCache
); );
} }
} }
if (schema.anyOf !== undefined) { if (schema.anyOf !== undefined) {
Object.assign(response, getExampleFromSchema(schema.anyOf[0], options, level + 1)); Object.assign(
response,
getExampleFromSchema(
schema.anyOf[0],
options,
level + 1,
undefined,
undefined,
resultCache
)
);
} else if (schema.oneOf !== undefined) { } else if (schema.oneOf !== undefined) {
Object.assign(response, getExampleFromSchema(schema.oneOf[0], options, level + 1)); Object.assign(
response,
getExampleFromSchema(
schema.oneOf[0],
options,
level + 1,
undefined,
undefined,
resultCache
)
);
} else if (schema.allOf !== undefined) { } else if (schema.allOf !== undefined) {
Object.assign( Object.assign(
response, response,
...schema.allOf ...schema.allOf
.map((item: Record<string, any>) => .map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema) getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
) )
.filter((item: any) => item !== undefined) .filter((item: any) => item !== undefined)
); );
@@ -335,7 +360,9 @@ const getExampleFromSchema = (
{ type: 'object', allOf: schema.items.allOf }, { type: 'object', allOf: schema.items.allOf },
options, options,
level + 1, level + 1,
schema schema,
undefined,
resultCache
); );
return cache( return cache(
@@ -346,7 +373,14 @@ const getExampleFromSchema = (
// For non-objects (like strings), collect all examples // For non-objects (like strings), collect all examples
const examples = schema.items.allOf const examples = schema.items.allOf
.map((item: Record<string, any>) => .map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema) getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
) )
.filter((item: any) => item !== undefined); .filter((item: any) => item !== undefined);
@@ -368,7 +402,14 @@ const getExampleFromSchema = (
const schemas = schema.items[rule].slice(0, 1); const schemas = schema.items[rule].slice(0, 1);
const exampleFromRule = schemas const exampleFromRule = schemas
.map((item: Record<string, any>) => .map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema) getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
) )
.filter((item: any) => item !== undefined); .filter((item: any) => item !== undefined);
@@ -380,7 +421,14 @@ const getExampleFromSchema = (
} }
if (schema.items?.type) { if (schema.items?.type) {
const exampleFromSchema = getExampleFromSchema(schema.items, options, level + 1); const exampleFromSchema = getExampleFromSchema(
schema.items,
options,
level + 1,
undefined,
undefined,
resultCache
);
return wrapItems ? [{ [itemsXmlTagName]: exampleFromSchema }] : [exampleFromSchema]; return wrapItems ? [{ [itemsXmlTagName]: exampleFromSchema }] : [exampleFromSchema];
} }
@@ -407,7 +455,14 @@ const getExampleFromSchema = (
const firstOneOfItem = discriminateSchema[0]; const firstOneOfItem = discriminateSchema[0];
// Return an example for the first item // Return an example for the first item
return getExampleFromSchema(firstOneOfItem, options, level + 1); return getExampleFromSchema(
firstOneOfItem,
options,
level + 1,
undefined,
undefined,
resultCache
);
} }
// Check if schema has the `allOf` key // Check if schema has the `allOf` key
@@ -417,7 +472,14 @@ const getExampleFromSchema = (
// Loop through all `allOf` schemas // Loop through all `allOf` schemas
schema.allOf.forEach((allOfItem: Record<string, any>) => { schema.allOf.forEach((allOfItem: Record<string, any>) => {
// Return an example from the schema // Return an example from the schema
const newExample = getExampleFromSchema(allOfItem, options, level + 1); const newExample = getExampleFromSchema(
allOfItem,
options,
level + 1,
undefined,
undefined,
resultCache
);
// Merge or overwrite the example // Merge or overwrite the example
example = example =
@@ -16,8 +16,12 @@ export function OpenAPISchemas(props: {
className?: string; className?: string;
data: OpenAPISchemasData; data: OpenAPISchemasData;
context: OpenAPISchemasContextProps; context: OpenAPISchemasContextProps;
/**
* Whether to show the schema directly if there is only one.
*/
grouped?: boolean;
}) { }) {
const { className, data, context } = props; const { className, data, context, grouped } = props;
const { schemas } = data; const { schemas } = data;
const clientContext: OpenAPIClientContext = { const clientContext: OpenAPIClientContext = {
@@ -32,7 +36,7 @@ export function OpenAPISchemas(props: {
return ( return (
<div className={clsx('openapi-schemas', className)}> <div className={clsx('openapi-schemas', className)}>
<OpenAPIRootSchemasSchema schemas={schemas} context={clientContext} /> <OpenAPIRootSchemasSchema grouped={grouped} schemas={schemas} context={clientContext} />
</div> </div>
); );
} }
@@ -44,11 +48,12 @@ export function OpenAPISchemas(props: {
function OpenAPIRootSchemasSchema(props: { function OpenAPIRootSchemasSchema(props: {
schemas: OpenAPISchemasData['schemas']; schemas: OpenAPISchemasData['schemas'];
context: OpenAPIClientContext; context: OpenAPIClientContext;
grouped?: boolean;
}) { }) {
const { schemas, context } = props; const { schemas, context, grouped } = props;
// If there is only one model, we show it directly. // If there is only one model and we are not grouping, we show it directly.
if (schemas.length === 1) { if (schemas.length === 1 && !grouped) {
const schema = schemas?.[0]?.schema; const schema = schemas?.[0]?.schema;
if (!schema) { if (!schema) {