Skip to content

Commit 27fb9c0

Browse files
Add Callbacks Support to V3 (#700)
* Add Callbacks support (#691) * add support to callbacks in openapi specs * set package manager in package json * implement operations as tabs within request panel * render callbacks below Request and Responses * remove unwanted files * rename create file * restore json settings * convert OperationTabs to typescript * fix linter * fix warning on lint order
1 parent 1207af7 commit 27fb9c0

File tree

9 files changed

+409
-11
lines changed

9 files changed

+409
-11
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,6 @@
7676
},
7777
"engines": {
7878
"node": ">=14"
79-
}
79+
},
80+
"packageManager": "yarn@1.22.1"
8081
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* ============================================================================
2+
* Copyright (c) Palo Alto Networks
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
* ========================================================================== */
7+
8+
import { createDescription } from "./createDescription";
9+
import { createMethodEndpoint } from "./createMethodEndpoint";
10+
import { createRequestBodyDetails } from "./createRequestBodyDetails";
11+
import { createStatusCodes } from "./createStatusCodes";
12+
import { create } from "./utils";
13+
import { MediaTypeObject } from "../openapi/types";
14+
import { ApiItem } from "../types";
15+
16+
interface Props {
17+
callbacks: ApiItem["callbacks"];
18+
}
19+
20+
interface RequestBodyProps {
21+
title: string;
22+
body: {
23+
content?: {
24+
[key: string]: MediaTypeObject;
25+
};
26+
description?: string;
27+
required?: boolean;
28+
};
29+
}
30+
31+
export function createCallbacks({ callbacks }: Props) {
32+
if (callbacks === undefined) {
33+
return undefined;
34+
}
35+
36+
const callbacksNames = Object.keys(callbacks);
37+
if (callbacksNames.length === 0) {
38+
return undefined;
39+
}
40+
41+
return create("div", {
42+
children: [
43+
create("div", {
44+
className: "openapi__divider",
45+
}),
46+
create("h2", {
47+
children: "Callbacks",
48+
id: "callbacks",
49+
}),
50+
create("OperationTabs", {
51+
className: "openapi-tabs__operation",
52+
children: callbacksNames.flatMap((name) => {
53+
const path = Object.keys(callbacks[name])[0];
54+
const methods = new Map([
55+
["delete", callbacks[name][path].delete],
56+
["get", callbacks[name][path].get],
57+
["head", callbacks[name][path].head],
58+
["options", callbacks[name][path].options],
59+
["patch", callbacks[name][path].patch],
60+
["post", callbacks[name][path].post],
61+
["put", callbacks[name][path].put],
62+
["trace", callbacks[name][path].trace],
63+
]);
64+
65+
return Array.from(methods).flatMap(([method, operationObject]) => {
66+
if (!operationObject) return [];
67+
68+
const { description, requestBody, responses } = operationObject;
69+
70+
return [
71+
create("TabItem", {
72+
label: `${method.toUpperCase()} ${name}`,
73+
value: `${method}-${name}`,
74+
children: [
75+
createMethodEndpoint(method, path),
76+
// TODO: add `deprecation notice` when markdown support is added
77+
createDescription(description),
78+
createRequestBodyDetails({
79+
title: "Body",
80+
body: requestBody,
81+
} as RequestBodyProps),
82+
createStatusCodes({
83+
id: "callbacks-responses",
84+
label: "Callbacks Responses",
85+
responses,
86+
}),
87+
],
88+
}),
89+
];
90+
});
91+
}),
92+
}),
93+
],
94+
});
95+
}

packages/docusaurus-plugin-openapi-docs/src/markdown/createRequestBodyDetails.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ interface Props {
1919
};
2020
}
2121

22-
export function createRequestBodyDetails({ title, body }: Props): any {
22+
export function createRequestBodyDetails({ title, body }: Props) {
2323
return createRequestSchema({ title, body });
2424
}

packages/docusaurus-plugin-openapi-docs/src/markdown/createStatusCodes.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export default function json2xml(o: any, tab: any) {
5454
}
5555

5656
interface Props {
57+
id?: string;
58+
label?: string;
5759
responses: ApiItem["responses"];
5860
}
5961

@@ -254,7 +256,7 @@ export function createExampleFromSchema(schema: any, mimeType: string) {
254256
return undefined;
255257
}
256258

257-
export function createStatusCodes({ responses }: Props) {
259+
export function createStatusCodes({ label, id, responses }: Props) {
258260
if (responses === undefined) {
259261
return undefined;
260262
}
@@ -269,6 +271,8 @@ export function createStatusCodes({ responses }: Props) {
269271
create("div", {
270272
children: [
271273
create("ApiTabs", {
274+
label,
275+
id,
272276
children: codes.map((code) => {
273277
const responseHeaders: any = responses[code].headers;
274278
return create("TabItem", {

packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { createAuthentication } from "./createAuthentication";
99
import { createAuthorization } from "./createAuthorization";
10+
import { createCallbacks } from "./createCallbacks";
1011
import { createContactInfo } from "./createContactInfo";
1112
import { createDeprecationNotice } from "./createDeprecationNotice";
1213
import { createDescription } from "./createDescription";
@@ -31,7 +32,7 @@ import {
3132
} from "../openapi/types";
3233
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
3334

34-
interface Props {
35+
interface RequestBodyProps {
3536
title: string;
3637
body: {
3738
content?: {
@@ -54,6 +55,7 @@ export function createApiPageMD({
5455
parameters,
5556
requestBody,
5657
responses,
58+
callbacks,
5759
},
5860
infoPath,
5961
frontMatter,
@@ -68,11 +70,14 @@ export function createApiPageMD({
6870
`import ResponseSamples from "@theme/ResponseSamples";\n`,
6971
`import SchemaItem from "@theme/SchemaItem";\n`,
7072
`import SchemaTabs from "@theme/SchemaTabs";\n`,
73+
`import OperationTabs from "@theme/OperationTabs";\n`,
7174
`import TabItem from "@theme/TabItem";\n\n`,
7275
createHeading(title),
7376
createMethodEndpoint(method, path),
7477
infoPath && createAuthorization(infoPath),
75-
frontMatter.show_extensions && createVendorExtensions(extensions),
78+
frontMatter.show_extensions
79+
? createVendorExtensions(extensions)
80+
: undefined,
7681
createDeprecationNotice({ deprecated, description: deprecatedDescription }),
7782
createDescription(description),
7883
createRequestHeader("Request"),
@@ -83,8 +88,9 @@ export function createApiPageMD({
8388
createRequestBodyDetails({
8489
title: "Body",
8590
body: requestBody,
86-
} as Props),
91+
} as RequestBodyProps),
8792
createStatusCodes({ responses }),
93+
createCallbacks({ callbacks }),
8894
]);
8995
}
9096

packages/docusaurus-theme-openapi-docs/src/theme/ApiTabs/index.tsx

+12-5
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,20 @@ import useIsBrowser from "@docusaurus/useIsBrowser";
2424
import Heading from "@theme/Heading";
2525
import clsx from "clsx";
2626

27+
export interface TabListProps extends TabProps {
28+
label: string;
29+
id: string;
30+
}
31+
2732
function TabList({
2833
className,
2934
block,
3035
selectedValue,
3136
selectValue,
3237
tabValues,
33-
}: TabProps & ReturnType<typeof useTabs>) {
38+
label = "Responses",
39+
id = "responses",
40+
}: TabListProps & ReturnType<typeof useTabs>) {
3441
const tabRefs: (HTMLLIElement | null)[] = [];
3542
const { blockElementScrollPositionUntilNextRender } =
3643
useScrollPositionBlocker();
@@ -107,8 +114,8 @@ function TabList({
107114

108115
return (
109116
<div className="openapi-tabs__response-header-section">
110-
<Heading as="h2" id="responses" className="openapi-tabs__response-header">
111-
Responses
117+
<Heading as="h2" id={id} className="openapi-tabs__response-header">
118+
{label}
112119
</Heading>
113120
<div className="openapi-tabs__response-container">
114121
{showTabArrows && (
@@ -199,7 +206,7 @@ function TabContent({
199206
</div>
200207
);
201208
}
202-
function TabsComponent(props: TabProps): React.JSX.Element {
209+
function TabsComponent(props: TabListProps): React.JSX.Element {
203210
const tabs = useTabs(props);
204211
return (
205212
<div className="openapi-tabs__container">
@@ -208,7 +215,7 @@ function TabsComponent(props: TabProps): React.JSX.Element {
208215
</div>
209216
);
210217
}
211-
export default function ApiTabs(props: TabProps): React.JSX.Element {
218+
export default function ApiTabs(props: TabListProps): React.JSX.Element {
212219
const isBrowser = useIsBrowser();
213220
return (
214221
<TabsComponent
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
.openapi-tabs__operation-container {
9+
display: flex;
10+
align-items: center;
11+
margin-top: 1rem;
12+
overflow: hidden;
13+
}
14+
15+
.openapi-tabs__operation-item {
16+
display: flex;
17+
align-items: center;
18+
justify-content: center;
19+
padding: 0.35rem 0.7rem;
20+
border: 1px solid transparent;
21+
margin-top: 0 !important;
22+
margin-right: 0.5rem;
23+
font-weight: var(--ifm-font-weight-bold);
24+
font-size: 12px;
25+
white-space: nowrap;
26+
transition: 300ms;
27+
28+
&:hover {
29+
background-color: transparent;
30+
border: 1px solid var(--ifm-toc-border-color);
31+
}
32+
33+
&.active {
34+
border: 1px solid var(--ifm-tabs-color-active-border);
35+
color: var(--ifm-tabs-color-active);
36+
}
37+
38+
&:last-child {
39+
margin-right: 0 !important;
40+
}
41+
}
42+
43+
.openapi-tabs__operation-list-container {
44+
overflow-y: hidden;
45+
overflow-x: scroll;
46+
scroll-behavior: smooth;
47+
48+
&::-webkit-scrollbar {
49+
display: none;
50+
}
51+
}
52+
53+
.openapi-tabs__operation-schema-container {
54+
max-width: 600px;
55+
}
56+
57+
@media screen and (max-width: 500px) {
58+
.operationTabsTopSection {
59+
flex-direction: column;
60+
align-items: flex-start;
61+
}
62+
63+
.operationTabsContainer {
64+
width: 100%;
65+
margin-top: var(--ifm-spacing-vertical);
66+
padding: 0;
67+
}
68+
}

0 commit comments

Comments
 (0)