Skip to content

Commit 0aff6bc

Browse files
committed
v1 models
1 parent 7aad9f7 commit 0aff6bc

File tree

8 files changed

+112
-24
lines changed

8 files changed

+112
-24
lines changed

packages/gitbook/src/components/DocumentView/OpenAPI/style.css

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
@apply flex-1 flex flex-col gap-4 mb-14;
44
}
55

6+
.openapi-models {
7+
@apply flex flex-col mb-14 flex-1;
8+
}
9+
610
.openapi-columns {
711
@apply grid grid-cols-1 lg:grid-cols-2 gap-6 print-mode:grid-cols-1 justify-stretch;
812
}
@@ -189,7 +193,7 @@
189193
@apply select-all font-mono font-normal text-tint-strong;
190194
}
191195

192-
.openapi-schema-propertyname[data-deprecated="true"] {
196+
.openapi-schema-propertyname[data-deprecated='true'] {
193197
@apply line-through opacity-9;
194198
}
195199

@@ -398,7 +402,7 @@
398402
-ms-overflow-style: none;
399403
}
400404

401-
.openapi-path-title[data-deprecated="true"] {
405+
.openapi-path-title[data-deprecated='true'] {
402406
@apply line-through;
403407
}
404408

@@ -477,7 +481,7 @@
477481
@apply transition-all;
478482
}
479483

480-
.openapi-section-toggle[aria-expanded="true"] > svg {
484+
.openapi-section-toggle[aria-expanded='true'] > svg {
481485
@apply rotate-90;
482486
}
483487

@@ -500,7 +504,7 @@
500504
@apply hover:bg-primary-hover whitespace-nowrap font-mono font-normal tabular-nums hover:text-primary cursor-pointer transition-all relative text-[0.813rem] text-tint px-1 border border-transparent rounded;
501505
}
502506

503-
.openapi-tabs-tab[aria-selected="true"] {
507+
.openapi-tabs-tab[aria-selected='true'] {
504508
@apply text-primary after:absolute after:-bottom-2 after:left-0 after:w-full after:h-px after:bg-primary-solid after:transition-all;
505509
}
506510

@@ -538,7 +542,7 @@
538542
@apply invisible;
539543
}
540544

541-
.openapi-disclosure-group-trigger[aria-expanded="true"] .openapi-response-description {
545+
.openapi-disclosure-group-trigger[aria-expanded='true'] .openapi-response-description {
542546
@apply whitespace-normal;
543547
}
544548

@@ -554,7 +558,7 @@
554558
@apply pb-2.5;
555559
}
556560

557-
.openapi-disclosure-group-trigger[aria-expanded="true"] > .openapi-disclosure-group-icon > svg {
561+
.openapi-disclosure-group-trigger[aria-expanded='true'] > .openapi-disclosure-group-icon > svg {
558562
@apply rotate-90;
559563
}
560564

@@ -583,19 +587,19 @@
583587
@apply size-3 shrink-0 transition-transform duration-300;
584588
}
585589

586-
.openapi-disclosure-trigger[aria-expanded="true"] svg {
590+
.openapi-disclosure-trigger[aria-expanded='true'] svg {
587591
@apply rotate-45;
588592
}
589593

590-
.openapi-disclosure-trigger[aria-expanded="true"] {
594+
.openapi-disclosure-trigger[aria-expanded='true'] {
591595
@apply w-full rounded-lg border-b rounded-b-none;
592596
}
593597

594-
.openapi-disclosure-trigger[aria-expanded="false"] {
598+
.openapi-disclosure-trigger[aria-expanded='false'] {
595599
@apply w-auto;
596600
}
597601

598-
.openapi-disclosure-panel[aria-hidden="false"] {
602+
.openapi-disclosure-panel[aria-hidden='false'] {
599603
@apply border-b border-x border-tint-subtle rounded-b-lg;
600604
}
601605

packages/react-openapi/src/OpenAPIDisclosureGroup.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@ interface Props {
1717
type TDisclosureGroup = {
1818
id: string;
1919
label: string | React.ReactNode;
20-
tabs?: {
21-
id: string;
22-
label: string | React.ReactNode;
23-
body?: React.ReactNode;
24-
}[];
25-
};
20+
} & (
21+
| {
22+
tabs?: {
23+
id: string;
24+
label: string | React.ReactNode;
25+
body?: React.ReactNode;
26+
}[];
27+
}
28+
| {
29+
body?: React.ReactNode;
30+
}
31+
);
2632

2733
const DisclosureGroupStateContext = createContext<DisclosureGroupState | null>(null);
2834

@@ -61,7 +67,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
6167

6268
const panelRef = useRef<HTMLDivElement | null>(null);
6369
const triggerRef = useRef<HTMLButtonElement | null>(null);
64-
const isDisabled = groupState?.isDisabled || !group.tabs?.length || false;
70+
const isDisabled = groupState?.isDisabled || ('tabs' in group && !group.tabs?.length) || false;
6571
const { buttonProps: triggerProps, panelProps } = useDisclosure(
6672
{
6773
...props,
@@ -74,9 +80,19 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
7480
const { buttonProps } = useButton(triggerProps, triggerRef);
7581
const { isFocusVisible, focusProps } = useFocusRing();
7682

77-
const defaultTab = group.tabs?.[0]?.id || '';
83+
const defaultTab =
84+
'tabs' in group && group.tabs?.[0]
85+
? (group.tabs[0]?.id ?? '')
86+
: 'body' in group
87+
? 'body'
88+
: '';
7889
const [selectedTabKey, setSelectedTabKey] = useState(defaultTab);
79-
const selectedTab = group.tabs?.find((tab) => tab.id === selectedTabKey);
90+
const selectedTab =
91+
'tabs' in group
92+
? group.tabs?.find((tab) => tab.id === selectedTabKey)
93+
: 'body' in group
94+
? { id: 'body', body: group.body }
95+
: null;
8096

8197
return (
8298
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
@@ -103,7 +119,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
103119

104120
{group.label}
105121
</button>
106-
{group.tabs ? (
122+
{'tabs' in group && group.tabs ? (
107123
<div className="openapi-disclosure-group-mediatype">
108124
{group.tabs?.length > 1 ? (
109125
<select
@@ -121,7 +137,7 @@ function DisclosureItem(props: { group: TDisclosureGroup; icon?: React.ReactNode
121137
</option>
122138
))}
123139
</select>
124-
) : group.tabs[0] ? (
140+
) : group.tabs[0]?.label ? (
125141
<span>{group.tabs[0].label}</span>
126142
) : null}
127143
</div>

packages/react-openapi/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export * from './resolveOpenAPIOperation';
1+
export * from './models';
22
export * from './OpenAPIOperation';
33
export * from './OpenAPIOperationContext';
4+
export * from './resolveOpenAPIOperation';
45
export type { OpenAPIOperationData } from './types';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function OpenAPIModelSchema(): JSX.Element {
2+
return <></>;
3+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import clsx from 'clsx';
2+
3+
import { OpenAPIDisclosureGroup } from '../OpenAPIDisclosureGroup';
4+
import { OpenAPISchemaProperty } from '../OpenAPISchema';
5+
import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from '../types';
6+
7+
/**
8+
* Display OpenAPI Models.
9+
*/
10+
export function OpenAPIModels(props: {
11+
className?: string;
12+
data: OpenAPIOperationData;
13+
context: OpenAPIContextProps;
14+
}) {
15+
const { className, data, context } = props;
16+
const { components } = data;
17+
18+
const clientContext: OpenAPIClientContext = {
19+
defaultInteractiveOpened: context.defaultInteractiveOpened,
20+
icons: context.icons,
21+
blockKey: context.blockKey,
22+
};
23+
24+
return (
25+
<div className={clsx('openapi-models', className)}>
26+
{components.length ? (
27+
<OpenAPIDisclosureGroup
28+
allowsMultipleExpanded
29+
icon={context.icons.chevronRight}
30+
groups={components.map(([name, schema]) => ({
31+
id: name,
32+
label: (
33+
<div className="openapi-response-tab-content" key={`model-${name}`}>
34+
<span className="openapi-response-statuscode">{name}</span>
35+
</div>
36+
),
37+
body: <OpenAPISchemaProperty schema={schema} context={clientContext} />,
38+
}))}
39+
/>
40+
) : null}
41+
</div>
42+
);
43+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { OpenAPIModels } from './OpenAPIModels';

packages/react-openapi/src/resolveOpenAPIOperation.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import {
66
type OpenAPIV3_1,
77
type OpenAPIV3xDocument,
88
dereference,
9+
shouldIgnoreEntity,
910
} from '@gitbook/openapi-parser';
1011
import type { OpenAPIOperationData } from './types';
1112
import { checkIsReference } from './utils';
1213

13-
export { toJSON, fromJSON };
14+
export { fromJSON, toJSON };
1415

1516
/**
1617
* Resolve an OpenAPI operation in a file and compile it to a more usable format.
@@ -39,7 +40,7 @@ export async function resolveOpenAPIOperation(
3940
};
4041
}
4142

42-
const servers = 'servers' in schema ? (schema.servers ?? []) : [];
43+
const servers = 'servers' in schema ? schema.servers ?? [] : [];
4344
const security = flattenSecurities(operation.security ?? schema.security ?? []);
4445

4546
// Resolve securities
@@ -54,12 +55,15 @@ export async function resolveOpenAPIOperation(
5455
}
5556
}
5657

58+
const components = flattenComponents(schema);
59+
5760
return {
5861
servers,
5962
operation,
6063
method,
6164
path,
6265
securities,
66+
components,
6367
'x-codeSamples':
6468
typeof schema['x-codeSamples'] === 'boolean' ? schema['x-codeSamples'] : undefined,
6569
'x-hideTryItPanel':
@@ -162,3 +166,16 @@ function flattenSecurities(security: OpenAPIV3.SecurityRequirementObject[]) {
162166
}));
163167
});
164168
}
169+
170+
function flattenComponents(
171+
schema: OpenAPIV3.Document | OpenAPIV3_1.Document
172+
): [string, OpenAPIV3.SchemaObject][] {
173+
const components = Object.keys(schema?.components?.schemas ?? {}).length
174+
? schema?.components?.schemas
175+
: {};
176+
177+
return Object.entries(components ?? {})
178+
.filter(([, schema]) => !shouldIgnoreEntity(schema))
179+
.sort((a, b) => a[0].localeCompare(b[0]))
180+
.map(([name, schema]) => [name, schema]);
181+
}

packages/react-openapi/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,7 @@ export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
5454

5555
/** Securities that should be used for this operation */
5656
securities: [string, OpenAPIV3.SecuritySchemeObject][];
57+
58+
/** Components schemas */
59+
components: [string, OpenAPIV3.SchemaObject][];
5760
}

0 commit comments

Comments
 (0)