@gitbook/react-openapi 1.1.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/InteractiveSection.d.ts +4 -0
- package/dist/InteractiveSection.jsx +11 -11
- package/dist/OpenAPICodeSample.d.ts +2 -1
- package/dist/OpenAPICodeSample.jsx +6 -5
- package/dist/OpenAPICodeSampleInteractive.d.ts +3 -0
- package/dist/OpenAPICodeSampleInteractive.jsx +19 -43
- package/dist/OpenAPICodeSampleSelector.d.ts +3 -4
- package/dist/OpenAPICodeSampleSelector.jsx +6 -11
- package/dist/OpenAPICopyButton.d.ts +2 -0
- package/dist/OpenAPICopyButton.jsx +5 -2
- package/dist/OpenAPIDisclosure.d.ts +4 -3
- package/dist/OpenAPIDisclosure.jsx +8 -11
- package/dist/OpenAPIDisclosureGroup.d.ts +7 -3
- package/dist/OpenAPIDisclosureGroup.jsx +18 -18
- package/dist/OpenAPIExample.d.ts +4 -22
- package/dist/OpenAPIExample.jsx +5 -72
- package/dist/OpenAPIMediaType.d.ts +21 -0
- package/dist/OpenAPIMediaType.jsx +61 -0
- package/dist/OpenAPIOperation.d.ts +3 -2
- package/dist/OpenAPIOperation.jsx +9 -68
- package/dist/OpenAPIOperationDescription.d.ts +9 -0
- package/dist/OpenAPIOperationDescription.jsx +22 -0
- package/dist/OpenAPIOperationStability.d.ts +9 -0
- package/dist/OpenAPIOperationStability.jsx +27 -0
- package/dist/OpenAPIPath.d.ts +2 -0
- package/dist/OpenAPIPath.jsx +3 -2
- package/dist/OpenAPIRequestBody.d.ts +3 -1
- package/dist/OpenAPIRequestBody.jsx +4 -3
- package/dist/OpenAPIResponse.d.ts +1 -1
- package/dist/OpenAPIResponse.jsx +1 -1
- package/dist/OpenAPIResponseExample.d.ts +3 -2
- package/dist/OpenAPIResponseExample.jsx +24 -63
- package/dist/OpenAPIResponseExampleContent.d.ts +19 -0
- package/dist/OpenAPIResponseExampleContent.jsx +57 -0
- package/dist/OpenAPIResponses.d.ts +1 -1
- package/dist/OpenAPIResponses.jsx +49 -36
- package/dist/OpenAPISchema.d.ts +1 -1
- package/dist/OpenAPISchema.jsx +103 -15
- package/dist/OpenAPISchemaName.d.ts +2 -0
- package/dist/OpenAPISchemaName.jsx +19 -10
- package/dist/OpenAPISchemaServer.d.ts +1 -1
- package/dist/OpenAPISecurities.d.ts +2 -1
- package/dist/OpenAPISecurities.jsx +11 -10
- package/dist/OpenAPISelect.d.ts +10 -3
- package/dist/OpenAPISelect.jsx +20 -9
- package/dist/OpenAPISpec.d.ts +3 -2
- package/dist/OpenAPISpec.jsx +11 -9
- package/dist/OpenAPIWebhook.d.ts +10 -0
- package/dist/OpenAPIWebhook.jsx +23 -0
- package/dist/OpenAPIWebhookExample.d.ts +6 -0
- package/dist/OpenAPIWebhookExample.jsx +41 -0
- package/dist/ScalarApiButton.d.ts +2 -0
- package/dist/ScalarApiButton.jsx +4 -3
- package/dist/StaticSection.d.ts +4 -1
- package/dist/StaticSection.jsx +13 -4
- package/dist/code-samples.js +57 -39
- package/dist/common/OpenAPIColumnSpec.d.ts +6 -0
- package/dist/common/OpenAPIColumnSpec.jsx +20 -0
- package/dist/common/OpenAPIOperationDescription.d.ts +6 -0
- package/dist/common/OpenAPIOperationDescription.jsx +19 -0
- package/dist/common/OpenAPIStability.d.ts +4 -0
- package/dist/common/OpenAPIStability.jsx +15 -0
- package/dist/common/OpenAPISummary.d.ts +6 -0
- package/dist/common/OpenAPISummary.jsx +30 -0
- package/dist/context.d.ts +23 -2
- package/dist/context.js +32 -0
- package/dist/getOrCreateStoreByKey.d.ts +1 -1
- package/dist/getOrCreateStoreByKey.js +0 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -0
- package/dist/resolveOpenAPIWebhook.d.ts +11 -0
- package/dist/resolveOpenAPIWebhook.js +127 -0
- package/dist/schemas/OpenAPISchemas.d.ts +2 -2
- package/dist/schemas/OpenAPISchemas.jsx +19 -23
- package/dist/stringifyOpenAPI.d.ts +1 -1
- package/dist/stringifyOpenAPI.js +6 -3
- package/dist/translate.d.ts +10 -0
- package/dist/translate.jsx +75 -0
- package/dist/translations/de.d.ts +37 -0
- package/dist/translations/de.js +37 -0
- package/dist/translations/en.d.ts +37 -0
- package/dist/translations/en.js +37 -0
- package/dist/translations/es.d.ts +37 -0
- package/dist/translations/es.js +37 -0
- package/dist/translations/fr.d.ts +37 -0
- package/dist/translations/fr.js +37 -0
- package/dist/translations/index.d.ts +341 -0
- package/dist/translations/index.js +27 -0
- package/dist/translations/ja.d.ts +37 -0
- package/dist/translations/ja.js +37 -0
- package/dist/translations/nl.d.ts +37 -0
- package/dist/translations/nl.js +37 -0
- package/dist/translations/no.d.ts +37 -0
- package/dist/translations/no.js +37 -0
- package/dist/translations/pt-br.d.ts +37 -0
- package/dist/translations/pt-br.js +37 -0
- package/dist/translations/types.d.ts +5 -0
- package/dist/translations/types.js +1 -0
- package/dist/translations/zh.d.ts +37 -0
- package/dist/translations/zh.js +37 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types.d.ts +8 -50
- package/dist/util/example.d.ts +35 -0
- package/dist/util/example.jsx +103 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +57 -0
- package/package.json +3 -3
- package/src/InteractiveSection.tsx +16 -14
- package/src/OpenAPICodeSample.tsx +22 -4
- package/src/OpenAPICodeSampleInteractive.tsx +38 -58
- package/src/OpenAPICodeSampleSelector.tsx +19 -12
- package/src/OpenAPICopyButton.tsx +7 -2
- package/src/OpenAPIDisclosure.tsx +20 -22
- package/src/OpenAPIDisclosureGroup.tsx +40 -22
- package/src/OpenAPIExample.tsx +8 -82
- package/src/OpenAPIMediaType.tsx +139 -0
- package/src/OpenAPIOperation.tsx +11 -100
- package/src/OpenAPIOperationDescription.tsx +34 -0
- package/src/OpenAPIOperationStability.tsx +39 -0
- package/src/OpenAPIPath.tsx +4 -1
- package/src/OpenAPIRequestBody.tsx +9 -4
- package/src/OpenAPIResponse.tsx +2 -2
- package/src/OpenAPIResponseExample.tsx +39 -108
- package/src/OpenAPIResponseExampleContent.tsx +123 -0
- package/src/OpenAPIResponses.tsx +83 -62
- package/src/OpenAPISchema.test.ts +80 -0
- package/src/OpenAPISchema.tsx +123 -16
- package/src/OpenAPISchemaName.tsx +26 -11
- package/src/OpenAPISchemaServer.tsx +1 -1
- package/src/OpenAPISecurities.tsx +33 -12
- package/src/OpenAPISelect.tsx +42 -16
- package/src/OpenAPISpec.tsx +21 -10
- package/src/OpenAPIWebhook.tsx +33 -0
- package/src/OpenAPIWebhookExample.tsx +60 -0
- package/src/ScalarApiButton.tsx +6 -6
- package/src/StaticSection.tsx +37 -5
- package/src/code-samples.test.ts +3 -1
- package/src/code-samples.ts +67 -54
- package/src/common/OpenAPIColumnSpec.tsx +31 -0
- package/src/common/OpenAPIOperationDescription.tsx +31 -0
- package/src/common/OpenAPIStability.tsx +23 -0
- package/src/common/OpenAPISummary.tsx +45 -0
- package/src/context.ts +37 -2
- package/src/getOrCreateStoreByKey.ts +1 -3
- package/src/index.ts +5 -1
- package/src/resolveOpenAPIWebhook.ts +99 -0
- package/src/schemas/OpenAPISchemas.tsx +34 -34
- package/src/stringifyOpenAPI.ts +11 -3
- package/src/translate.tsx +80 -0
- package/src/translations/de.ts +37 -0
- package/src/translations/en.ts +37 -0
- package/src/translations/es.ts +37 -0
- package/src/translations/fr.ts +37 -0
- package/src/translations/index.ts +33 -0
- package/src/translations/ja.ts +37 -0
- package/src/translations/nl.ts +37 -0
- package/src/translations/no.ts +37 -0
- package/src/translations/pt-br.ts +37 -0
- package/src/translations/types.ts +7 -0
- package/src/translations/zh.ts +37 -0
- package/src/types.ts +11 -53
- package/src/util/example.tsx +129 -0
- package/src/utils.ts +67 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
|
+
import { Markdown } from './Markdown';
|
|
3
|
+
import type { OpenAPIContext } from './context';
|
|
4
|
+
import { resolveDescription } from './utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Display the description of an OpenAPI operation.
|
|
8
|
+
*/
|
|
9
|
+
export function OpenAPIOperationDescription(props: {
|
|
10
|
+
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
|
11
|
+
context: OpenAPIContext;
|
|
12
|
+
}) {
|
|
13
|
+
const { operation } = props;
|
|
14
|
+
if (operation['x-gitbook-description-document']) {
|
|
15
|
+
return (
|
|
16
|
+
<div className="openapi-intro">
|
|
17
|
+
{props.context.renderDocument({
|
|
18
|
+
document: operation['x-gitbook-description-document'],
|
|
19
|
+
})}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const description = resolveDescription(operation);
|
|
25
|
+
if (!description) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="openapi-intro">
|
|
31
|
+
<Markdown className="openapi-description" source={description} />
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OpenAPIStability } from '@gitbook/openapi-parser';
|
|
2
|
+
import type { OpenAPIContext } from './context';
|
|
3
|
+
import { t } from './translate';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Display the stability of an OpenAPI operation.
|
|
7
|
+
*/
|
|
8
|
+
export function OpenAPIOperationStability(props: {
|
|
9
|
+
stability: OpenAPIStability;
|
|
10
|
+
context: OpenAPIContext;
|
|
11
|
+
}) {
|
|
12
|
+
const { stability, context } = props;
|
|
13
|
+
|
|
14
|
+
const stabilityLabel = getStabilityLabel(stability, context);
|
|
15
|
+
|
|
16
|
+
if (!stabilityLabel) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className={`openapi-stability openapi-stability-${stability}`}>{stabilityLabel}</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the stability label for the given stability level.
|
|
27
|
+
*/
|
|
28
|
+
function getStabilityLabel(stability: OpenAPIStability, context: OpenAPIContext) {
|
|
29
|
+
switch (stability) {
|
|
30
|
+
case 'experimental':
|
|
31
|
+
return t(context.translation, 'stability_experimental');
|
|
32
|
+
case 'alpha':
|
|
33
|
+
return t(context.translation, 'stability_alpha');
|
|
34
|
+
case 'beta':
|
|
35
|
+
return t(context.translation, 'stability_beta');
|
|
36
|
+
default:
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/OpenAPIPath.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
|
2
|
+
import { type OpenAPIUniversalContext, getOpenAPIClientContext } from './context';
|
|
2
3
|
import type { OpenAPIOperationData } from './types';
|
|
3
4
|
import { getDefaultServerURL } from './util/server';
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ import { getDefaultServerURL } from './util/server';
|
|
|
7
8
|
*/
|
|
8
9
|
export function OpenAPIPath(props: {
|
|
9
10
|
data: OpenAPIOperationData;
|
|
11
|
+
context: OpenAPIUniversalContext;
|
|
10
12
|
/** Whether to show the server URL.
|
|
11
13
|
* @default true
|
|
12
14
|
*/
|
|
@@ -17,7 +19,7 @@ export function OpenAPIPath(props: {
|
|
|
17
19
|
*/
|
|
18
20
|
canCopy?: boolean;
|
|
19
21
|
}) {
|
|
20
|
-
const { data, withServer = true, canCopy = true } = props;
|
|
22
|
+
const { data, context, withServer = true, canCopy = true } = props;
|
|
21
23
|
const { method, path, operation } = data;
|
|
22
24
|
|
|
23
25
|
const server = getDefaultServerURL(data.servers);
|
|
@@ -41,6 +43,7 @@ export function OpenAPIPath(props: {
|
|
|
41
43
|
className="openapi-path-title"
|
|
42
44
|
data-deprecated={operation.deprecated}
|
|
43
45
|
isDisabled={!canCopy}
|
|
46
|
+
context={getOpenAPIClientContext(context)}
|
|
44
47
|
>
|
|
45
48
|
{element}
|
|
46
49
|
</OpenAPICopyButton>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import { InteractiveSection } from './InteractiveSection';
|
|
3
3
|
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
|
4
|
-
import type { OpenAPIClientContext } from './
|
|
5
|
-
import {
|
|
4
|
+
import type { OpenAPIClientContext } from './context';
|
|
5
|
+
import { t } from './translate';
|
|
6
|
+
import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
|
7
|
+
import { checkIsReference, createStateKey } from './utils';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Display an interactive request body.
|
|
@@ -10,8 +12,9 @@ import { checkIsReference } from './utils';
|
|
|
10
12
|
export function OpenAPIRequestBody(props: {
|
|
11
13
|
requestBody: OpenAPIV3.RequestBodyObject | OpenAPIV3.ReferenceObject;
|
|
12
14
|
context: OpenAPIClientContext;
|
|
15
|
+
data: OpenAPIOperationData | OpenAPIWebhookData;
|
|
13
16
|
}) {
|
|
14
|
-
const { requestBody, context } = props;
|
|
17
|
+
const { requestBody, context, data } = props;
|
|
15
18
|
|
|
16
19
|
if (checkIsReference(requestBody)) {
|
|
17
20
|
return null;
|
|
@@ -19,8 +22,10 @@ export function OpenAPIRequestBody(props: {
|
|
|
19
22
|
|
|
20
23
|
return (
|
|
21
24
|
<InteractiveSection
|
|
22
|
-
header=
|
|
25
|
+
header={t(context.translation, 'name' in data ? 'payload' : 'body')}
|
|
23
26
|
className="openapi-requestbody"
|
|
27
|
+
stateKey={createStateKey('request-body-media-type', context.blockKey)}
|
|
28
|
+
selectIcon={context.icons.chevronDown}
|
|
24
29
|
tabs={Object.entries(requestBody.content ?? {}).map(
|
|
25
30
|
([contentType, mediaTypeObject]) => {
|
|
26
31
|
return {
|
package/src/OpenAPIResponse.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
|
3
3
|
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
|
4
|
-
import type { OpenAPIClientContext } from './
|
|
4
|
+
import type { OpenAPIClientContext } from './context';
|
|
5
5
|
import { parameterToProperty, resolveDescription } from './utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -27,7 +27,7 @@ export function OpenAPIResponse(props: {
|
|
|
27
27
|
return (
|
|
28
28
|
<div className="openapi-response-body">
|
|
29
29
|
{headers.length > 0 ? (
|
|
30
|
-
<OpenAPIDisclosure
|
|
30
|
+
<OpenAPIDisclosure icon={context.icons.plus} label="Headers">
|
|
31
31
|
<OpenAPISchemaProperties
|
|
32
32
|
properties={headers.map(([name, header]) =>
|
|
33
33
|
parameterToProperty({ name, ...header })
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|
2
2
|
import { Markdown } from './Markdown';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from './
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
|
12
|
-
import { checkIsReference, createStateKey, resolveDescription } from './utils';
|
|
3
|
+
import { OpenAPIEmptyExample, OpenAPIExample } from './OpenAPIExample';
|
|
4
|
+
import { OpenAPIMediaTypeContent } from './OpenAPIMediaType';
|
|
5
|
+
import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
|
|
6
|
+
import { type OpenAPIContext, getOpenAPIClientContext } from './context';
|
|
7
|
+
import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
|
8
|
+
import { getExampleFromReference, getExamples } from './util/example';
|
|
9
|
+
import { createStateKey, getStatusCodeDefaultLabel } from './utils';
|
|
10
|
+
import { checkIsReference, resolveDescription } from './utils';
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* Display an example of the response content.
|
|
16
14
|
*/
|
|
17
15
|
export function OpenAPIResponseExample(props: {
|
|
18
|
-
data: OpenAPIOperationData;
|
|
16
|
+
data: OpenAPIOperationData | OpenAPIWebhookData;
|
|
19
17
|
context: OpenAPIContext;
|
|
20
18
|
}) {
|
|
21
19
|
const { data, context } = props;
|
|
@@ -45,36 +43,41 @@ export function OpenAPIResponseExample(props: {
|
|
|
45
43
|
|
|
46
44
|
const tabs = responses.map(([key, responseObject]) => {
|
|
47
45
|
const description = resolveDescription(responseObject);
|
|
46
|
+
const label = description ? (
|
|
47
|
+
<Markdown source={description} />
|
|
48
|
+
) : (
|
|
49
|
+
getStatusCodeDefaultLabel(key, context)
|
|
50
|
+
);
|
|
48
51
|
|
|
49
52
|
if (checkIsReference(responseObject)) {
|
|
50
53
|
return {
|
|
51
54
|
key: key,
|
|
52
|
-
label
|
|
55
|
+
label,
|
|
56
|
+
statusCode: key,
|
|
53
57
|
body: (
|
|
54
58
|
<OpenAPIExample
|
|
55
|
-
example={getExampleFromReference(responseObject)}
|
|
59
|
+
example={getExampleFromReference(responseObject, context)}
|
|
56
60
|
context={context}
|
|
57
61
|
syntax="json"
|
|
58
62
|
/>
|
|
59
63
|
),
|
|
60
|
-
footer: description ? <Markdown source={description} /> : undefined,
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
if (!responseObject.content || Object.keys(responseObject.content).length === 0) {
|
|
65
68
|
return {
|
|
66
69
|
key: key,
|
|
67
|
-
label
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
label,
|
|
71
|
+
statusCode: key,
|
|
72
|
+
body: <OpenAPIEmptyExample context={context} />,
|
|
70
73
|
};
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
return {
|
|
74
77
|
key: key,
|
|
75
|
-
label
|
|
78
|
+
label,
|
|
79
|
+
statusCode: key,
|
|
76
80
|
body: <OpenAPIResponse context={context} content={responseObject.content} />,
|
|
77
|
-
footer: description ? <Markdown source={description} /> : undefined,
|
|
78
81
|
};
|
|
79
82
|
});
|
|
80
83
|
|
|
@@ -83,11 +86,11 @@ export function OpenAPIResponseExample(props: {
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
return (
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
<OpenAPIResponseExampleContent
|
|
90
|
+
selectIcon={context.icons.chevronDown}
|
|
91
|
+
blockKey={context.blockKey}
|
|
92
|
+
items={tabs}
|
|
93
|
+
/>
|
|
91
94
|
);
|
|
92
95
|
}
|
|
93
96
|
|
|
@@ -106,98 +109,26 @@ function OpenAPIResponse(props: {
|
|
|
106
109
|
throw new Error('One media type is required');
|
|
107
110
|
}
|
|
108
111
|
|
|
109
|
-
if (entries.length === 1) {
|
|
110
|
-
const [mediaType, mediaTypeObject] = firstEntry;
|
|
111
|
-
return (
|
|
112
|
-
<OpenAPIResponseMediaType
|
|
113
|
-
context={context}
|
|
114
|
-
mediaType={mediaType}
|
|
115
|
-
mediaTypeObject={mediaTypeObject}
|
|
116
|
-
/>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
112
|
const tabs = entries.map((entry) => {
|
|
121
113
|
const [mediaType, mediaTypeObject] = entry;
|
|
122
114
|
return {
|
|
123
115
|
key: mediaType,
|
|
124
116
|
label: mediaType,
|
|
125
|
-
body:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
),
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<OpenAPITabs stateKey={createStateKey('response-media-types')} items={tabs}>
|
|
137
|
-
<StaticSection header={<OpenAPITabsList />} className="openapi-response-media-types">
|
|
138
|
-
<OpenAPITabsPanels />
|
|
139
|
-
</StaticSection>
|
|
140
|
-
</OpenAPITabs>
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function OpenAPIResponseMediaType(props: {
|
|
145
|
-
mediaTypeObject: OpenAPIV3.MediaTypeObject;
|
|
146
|
-
mediaType: string;
|
|
147
|
-
context: OpenAPIContext;
|
|
148
|
-
}) {
|
|
149
|
-
const { mediaTypeObject, mediaType } = props;
|
|
150
|
-
const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType });
|
|
151
|
-
const syntax = getSyntaxFromMediaType(mediaType);
|
|
152
|
-
const firstExample = examples[0];
|
|
153
|
-
|
|
154
|
-
if (!firstExample) {
|
|
155
|
-
return <OpenAPIEmptyExample />;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (examples.length === 1) {
|
|
159
|
-
return (
|
|
160
|
-
<OpenAPIExample
|
|
161
|
-
example={firstExample.example}
|
|
162
|
-
context={props.context}
|
|
163
|
-
syntax={syntax}
|
|
164
|
-
/>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const tabs = examples.map((example) => {
|
|
169
|
-
return {
|
|
170
|
-
key: example.key,
|
|
171
|
-
label: example.example.summary || example.key,
|
|
172
|
-
body: (
|
|
173
|
-
<OpenAPIExample example={example.example} context={props.context} syntax={syntax} />
|
|
174
|
-
),
|
|
117
|
+
body: <></>,
|
|
118
|
+
examples: getExamples({
|
|
119
|
+
mediaTypeObject,
|
|
120
|
+
mediaType,
|
|
121
|
+
context,
|
|
122
|
+
}),
|
|
175
123
|
};
|
|
176
124
|
});
|
|
177
125
|
|
|
178
126
|
return (
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
</StaticSection>
|
|
186
|
-
</OpenAPITabs>
|
|
127
|
+
<OpenAPIMediaTypeContent
|
|
128
|
+
selectIcon={context.icons.chevronDown}
|
|
129
|
+
stateKey={createStateKey('response-media-types', context.blockKey)}
|
|
130
|
+
items={tabs}
|
|
131
|
+
context={getOpenAPIClientContext(context)}
|
|
132
|
+
/>
|
|
187
133
|
);
|
|
188
134
|
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Get the syntax from a media type.
|
|
192
|
-
*/
|
|
193
|
-
function getSyntaxFromMediaType(mediaType: string): string {
|
|
194
|
-
if (mediaType.includes('json')) {
|
|
195
|
-
return 'json';
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (mediaType === 'application/xml') {
|
|
199
|
-
return 'xml';
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return 'text';
|
|
203
|
-
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import type { Key } from 'react-aria';
|
|
5
|
+
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
|
6
|
+
import { StaticSection } from './StaticSection';
|
|
7
|
+
import { createStateKey, getStatusCodeClassName } from './utils';
|
|
8
|
+
|
|
9
|
+
type OpenAPIResponseExampleItem = OpenAPISelectItem & {
|
|
10
|
+
statusCode: string;
|
|
11
|
+
body: React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the state of the response examples select.
|
|
16
|
+
*/
|
|
17
|
+
export function useResponseExamplesState(
|
|
18
|
+
blockKey: string | undefined,
|
|
19
|
+
initialKey: Key = 'default'
|
|
20
|
+
) {
|
|
21
|
+
return useSelectState(getResponseExampleStateKey(blockKey), initialKey);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function OpenAPIResponseExampleContent(props: {
|
|
25
|
+
items: OpenAPIResponseExampleItem[];
|
|
26
|
+
blockKey?: string;
|
|
27
|
+
selectIcon?: React.ReactNode;
|
|
28
|
+
}) {
|
|
29
|
+
const { blockKey, items, selectIcon } = props;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<StaticSection
|
|
33
|
+
header={
|
|
34
|
+
<OpenAPIResponseExampleHeader
|
|
35
|
+
selectIcon={selectIcon}
|
|
36
|
+
blockKey={blockKey}
|
|
37
|
+
items={items}
|
|
38
|
+
/>
|
|
39
|
+
}
|
|
40
|
+
className="openapi-response-examples"
|
|
41
|
+
>
|
|
42
|
+
<OpenAPIResponseExampleBody blockKey={blockKey} items={items} />
|
|
43
|
+
</StaticSection>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function OpenAPIResponseExampleHeader(props: {
|
|
48
|
+
items: OpenAPIResponseExampleItem[];
|
|
49
|
+
blockKey?: string;
|
|
50
|
+
selectIcon?: React.ReactNode;
|
|
51
|
+
}) {
|
|
52
|
+
const { items, blockKey, selectIcon } = props;
|
|
53
|
+
|
|
54
|
+
if (items.length === 1) {
|
|
55
|
+
const item = items[0];
|
|
56
|
+
|
|
57
|
+
if (!item) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<span className="openapi-response-examples-statuscode-title">
|
|
63
|
+
<span
|
|
64
|
+
className={clsx(
|
|
65
|
+
'openapi-statuscode',
|
|
66
|
+
`openapi-statuscode-${getStatusCodeClassName(item.statusCode)}`,
|
|
67
|
+
'openapi-response-examples-statuscode'
|
|
68
|
+
)}
|
|
69
|
+
>
|
|
70
|
+
{item.statusCode}
|
|
71
|
+
</span>
|
|
72
|
+
<span>{item.label}</span>
|
|
73
|
+
</span>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<OpenAPISelect
|
|
79
|
+
items={items}
|
|
80
|
+
icon={selectIcon}
|
|
81
|
+
stateKey={getResponseExampleStateKey(blockKey)}
|
|
82
|
+
placement="bottom start"
|
|
83
|
+
>
|
|
84
|
+
{items.map((item) => (
|
|
85
|
+
<OpenAPISelectItem key={item.key} id={item.key} value={item}>
|
|
86
|
+
<span
|
|
87
|
+
className={clsx(
|
|
88
|
+
'openapi-statuscode',
|
|
89
|
+
`openapi-statuscode-${getStatusCodeClassName(item.statusCode)}`,
|
|
90
|
+
'openapi-response-examples-statuscode'
|
|
91
|
+
)}
|
|
92
|
+
>
|
|
93
|
+
{item.statusCode}
|
|
94
|
+
</span>
|
|
95
|
+
<span>{item.label}</span>
|
|
96
|
+
</OpenAPISelectItem>
|
|
97
|
+
))}
|
|
98
|
+
</OpenAPISelect>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function OpenAPIResponseExampleBody(props: {
|
|
103
|
+
items: OpenAPIResponseExampleItem[];
|
|
104
|
+
blockKey?: string;
|
|
105
|
+
}) {
|
|
106
|
+
const { blockKey, items } = props;
|
|
107
|
+
const state = useResponseExamplesState(blockKey, items[0]?.key);
|
|
108
|
+
|
|
109
|
+
const selectedItem = items.find((item) => item.key === state.key) ?? items[0];
|
|
110
|
+
|
|
111
|
+
if (!selectedItem) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return <div className="openapi-response-examples-panel">{selectedItem.body}</div>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Return the state key for the response examples.
|
|
120
|
+
*/
|
|
121
|
+
function getResponseExampleStateKey(blockKey: string | undefined) {
|
|
122
|
+
return createStateKey('openapi-responses', blockKey);
|
|
123
|
+
}
|
package/src/OpenAPIResponses.tsx
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import type { OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
|
4
|
+
import clsx from 'clsx';
|
|
2
5
|
import { Markdown } from './Markdown';
|
|
3
6
|
import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
|
4
7
|
import { OpenAPIResponse } from './OpenAPIResponse';
|
|
8
|
+
import { useResponseExamplesState } from './OpenAPIResponseExampleContent';
|
|
5
9
|
import { StaticSection } from './StaticSection';
|
|
6
|
-
import type { OpenAPIClientContext } from './
|
|
10
|
+
import type { OpenAPIClientContext } from './context';
|
|
11
|
+
import { t } from './translate';
|
|
12
|
+
import { createStateKey, getStatusCodeClassName, getStatusCodeDefaultLabel } from './utils';
|
|
7
13
|
|
|
8
14
|
/**
|
|
9
15
|
* Display an interactive response body.
|
|
@@ -14,70 +20,85 @@ export function OpenAPIResponses(props: {
|
|
|
14
20
|
}) {
|
|
15
21
|
const { responses, context } = props;
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
),
|
|
41
|
-
},
|
|
42
|
-
];
|
|
43
|
-
}
|
|
23
|
+
const groups = Object.entries(responses).map(
|
|
24
|
+
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
|
|
25
|
+
const tabs = (() => {
|
|
26
|
+
// If there is no content, but there are headers, we need to show the headers
|
|
27
|
+
if (
|
|
28
|
+
(!response.content || !Object.keys(response.content).length) &&
|
|
29
|
+
response.headers &&
|
|
30
|
+
Object.keys(response.headers).length
|
|
31
|
+
) {
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
key: 'default',
|
|
35
|
+
label: '',
|
|
36
|
+
body: (
|
|
37
|
+
<OpenAPIResponse
|
|
38
|
+
response={response}
|
|
39
|
+
mediaType={{}}
|
|
40
|
+
context={context}
|
|
41
|
+
/>
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
})();
|
|
47
|
+
return Object.entries(response.content ?? {}).map(([contentType, mediaType]) => ({
|
|
48
|
+
key: contentType,
|
|
49
|
+
label: contentType,
|
|
50
|
+
body: (
|
|
51
|
+
<OpenAPIResponse
|
|
52
|
+
response={response}
|
|
53
|
+
mediaType={mediaType}
|
|
54
|
+
context={context}
|
|
55
|
+
/>
|
|
56
|
+
),
|
|
57
|
+
}));
|
|
58
|
+
})();
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
const description = response.description;
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
62
|
+
return {
|
|
63
|
+
key: statusCode,
|
|
64
|
+
label: (
|
|
65
|
+
<div className="openapi-response-tab-content">
|
|
66
|
+
<span
|
|
67
|
+
className={clsx(
|
|
68
|
+
'openapi-statuscode',
|
|
69
|
+
`openapi-statuscode-${getStatusCodeClassName(statusCode)}`
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{statusCode}
|
|
73
|
+
</span>
|
|
74
|
+
{description ? (
|
|
75
|
+
<Markdown
|
|
76
|
+
source={description}
|
|
77
|
+
className="openapi-response-description"
|
|
78
|
+
/>
|
|
79
|
+
) : (
|
|
80
|
+
getStatusCodeDefaultLabel(statusCode, context)
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
),
|
|
84
|
+
tabs,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<StaticSection header={t(context.translation, 'responses')} className="openapi-responses">
|
|
93
|
+
<OpenAPIDisclosureGroup
|
|
94
|
+
icon={context.icons.chevronRight}
|
|
95
|
+
expandedKeys={state.key ? new Set([state.key]) : new Set()}
|
|
96
|
+
onExpandedChange={(keys) => {
|
|
97
|
+
const key = keys.values().next().value ?? null;
|
|
98
|
+
state.setKey(key);
|
|
99
|
+
}}
|
|
100
|
+
groups={groups}
|
|
101
|
+
selectStateKey={createStateKey('response-media-types', context.blockKey)}
|
|
81
102
|
/>
|
|
82
103
|
</StaticSection>
|
|
83
104
|
);
|