Skip to content

Commit

Permalink
Add Callbacks Support to V3 (#700)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lucasassisrosa authored Jan 18, 2024
1 parent 1207af7 commit 27fb9c0
Show file tree
Hide file tree
Showing 9 changed files with 409 additions and 11 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@
},
"engines": {
"node": ">=14"
}
},
"packageManager": "[email protected]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* ============================================================================
* Copyright (c) Palo Alto Networks
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* ========================================================================== */

import { createDescription } from "./createDescription";
import { createMethodEndpoint } from "./createMethodEndpoint";
import { createRequestBodyDetails } from "./createRequestBodyDetails";
import { createStatusCodes } from "./createStatusCodes";
import { create } from "./utils";
import { MediaTypeObject } from "../openapi/types";
import { ApiItem } from "../types";

interface Props {
callbacks: ApiItem["callbacks"];
}

interface RequestBodyProps {
title: string;
body: {
content?: {
[key: string]: MediaTypeObject;
};
description?: string;
required?: boolean;
};
}

export function createCallbacks({ callbacks }: Props) {
if (callbacks === undefined) {
return undefined;
}

const callbacksNames = Object.keys(callbacks);
if (callbacksNames.length === 0) {
return undefined;
}

return create("div", {
children: [
create("div", {
className: "openapi__divider",
}),
create("h2", {
children: "Callbacks",
id: "callbacks",
}),
create("OperationTabs", {
className: "openapi-tabs__operation",
children: callbacksNames.flatMap((name) => {
const path = Object.keys(callbacks[name])[0];
const methods = new Map([
["delete", callbacks[name][path].delete],
["get", callbacks[name][path].get],
["head", callbacks[name][path].head],
["options", callbacks[name][path].options],
["patch", callbacks[name][path].patch],
["post", callbacks[name][path].post],
["put", callbacks[name][path].put],
["trace", callbacks[name][path].trace],
]);

return Array.from(methods).flatMap(([method, operationObject]) => {
if (!operationObject) return [];

const { description, requestBody, responses } = operationObject;

return [
create("TabItem", {
label: `${method.toUpperCase()} ${name}`,
value: `${method}-${name}`,
children: [
createMethodEndpoint(method, path),
// TODO: add `deprecation notice` when markdown support is added
createDescription(description),
createRequestBodyDetails({
title: "Body",
body: requestBody,
} as RequestBodyProps),
createStatusCodes({
id: "callbacks-responses",
label: "Callbacks Responses",
responses,
}),
],
}),
];
});
}),
}),
],
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ interface Props {
};
}

export function createRequestBodyDetails({ title, body }: Props): any {
export function createRequestBodyDetails({ title, body }: Props) {
return createRequestSchema({ title, body });
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export default function json2xml(o: any, tab: any) {
}

interface Props {
id?: string;
label?: string;
responses: ApiItem["responses"];
}

Expand Down Expand Up @@ -254,7 +256,7 @@ export function createExampleFromSchema(schema: any, mimeType: string) {
return undefined;
}

export function createStatusCodes({ responses }: Props) {
export function createStatusCodes({ label, id, responses }: Props) {
if (responses === undefined) {
return undefined;
}
Expand All @@ -269,6 +271,8 @@ export function createStatusCodes({ responses }: Props) {
create("div", {
children: [
create("ApiTabs", {
label,
id,
children: codes.map((code) => {
const responseHeaders: any = responses[code].headers;
return create("TabItem", {
Expand Down
12 changes: 9 additions & 3 deletions packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { createAuthentication } from "./createAuthentication";
import { createAuthorization } from "./createAuthorization";
import { createCallbacks } from "./createCallbacks";
import { createContactInfo } from "./createContactInfo";
import { createDeprecationNotice } from "./createDeprecationNotice";
import { createDescription } from "./createDescription";
Expand All @@ -31,7 +32,7 @@ import {
} from "../openapi/types";
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";

interface Props {
interface RequestBodyProps {
title: string;
body: {
content?: {
Expand All @@ -54,6 +55,7 @@ export function createApiPageMD({
parameters,
requestBody,
responses,
callbacks,
},
infoPath,
frontMatter,
Expand All @@ -68,11 +70,14 @@ export function createApiPageMD({
`import ResponseSamples from "@theme/ResponseSamples";\n`,
`import SchemaItem from "@theme/SchemaItem";\n`,
`import SchemaTabs from "@theme/SchemaTabs";\n`,
`import OperationTabs from "@theme/OperationTabs";\n`,
`import TabItem from "@theme/TabItem";\n\n`,
createHeading(title),
createMethodEndpoint(method, path),
infoPath && createAuthorization(infoPath),
frontMatter.show_extensions && createVendorExtensions(extensions),
frontMatter.show_extensions
? createVendorExtensions(extensions)
: undefined,
createDeprecationNotice({ deprecated, description: deprecatedDescription }),
createDescription(description),
createRequestHeader("Request"),
Expand All @@ -83,8 +88,9 @@ export function createApiPageMD({
createRequestBodyDetails({
title: "Body",
body: requestBody,
} as Props),
} as RequestBodyProps),
createStatusCodes({ responses }),
createCallbacks({ callbacks }),
]);
}

Expand Down
17 changes: 12 additions & 5 deletions packages/docusaurus-theme-openapi-docs/src/theme/ApiTabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,20 @@ import useIsBrowser from "@docusaurus/useIsBrowser";
import Heading from "@theme/Heading";
import clsx from "clsx";

export interface TabListProps extends TabProps {
label: string;
id: string;
}

function TabList({
className,
block,
selectedValue,
selectValue,
tabValues,
}: TabProps & ReturnType<typeof useTabs>) {
label = "Responses",
id = "responses",
}: TabListProps & ReturnType<typeof useTabs>) {
const tabRefs: (HTMLLIElement | null)[] = [];
const { blockElementScrollPositionUntilNextRender } =
useScrollPositionBlocker();
Expand Down Expand Up @@ -107,8 +114,8 @@ function TabList({

return (
<div className="openapi-tabs__response-header-section">
<Heading as="h2" id="responses" className="openapi-tabs__response-header">
Responses
<Heading as="h2" id={id} className="openapi-tabs__response-header">
{label}
</Heading>
<div className="openapi-tabs__response-container">
{showTabArrows && (
Expand Down Expand Up @@ -199,7 +206,7 @@ function TabContent({
</div>
);
}
function TabsComponent(props: TabProps): React.JSX.Element {
function TabsComponent(props: TabListProps): React.JSX.Element {
const tabs = useTabs(props);
return (
<div className="openapi-tabs__container">
Expand All @@ -208,7 +215,7 @@ function TabsComponent(props: TabProps): React.JSX.Element {
</div>
);
}
export default function ApiTabs(props: TabProps): React.JSX.Element {
export default function ApiTabs(props: TabListProps): React.JSX.Element {
const isBrowser = useIsBrowser();
return (
<TabsComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

.openapi-tabs__operation-container {
display: flex;
align-items: center;
margin-top: 1rem;
overflow: hidden;
}

.openapi-tabs__operation-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0.35rem 0.7rem;
border: 1px solid transparent;
margin-top: 0 !important;
margin-right: 0.5rem;
font-weight: var(--ifm-font-weight-bold);
font-size: 12px;
white-space: nowrap;
transition: 300ms;

&:hover {
background-color: transparent;
border: 1px solid var(--ifm-toc-border-color);
}

&.active {
border: 1px solid var(--ifm-tabs-color-active-border);
color: var(--ifm-tabs-color-active);
}

&:last-child {
margin-right: 0 !important;
}
}

.openapi-tabs__operation-list-container {
overflow-y: hidden;
overflow-x: scroll;
scroll-behavior: smooth;

&::-webkit-scrollbar {
display: none;
}
}

.openapi-tabs__operation-schema-container {
max-width: 600px;
}

@media screen and (max-width: 500px) {
.operationTabsTopSection {
flex-direction: column;
align-items: flex-start;
}

.operationTabsContainer {
width: 100%;
margin-top: var(--ifm-spacing-vertical);
padding: 0;
}
}
Loading

0 comments on commit 27fb9c0

Please sign in to comment.