Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Callbacks Support to V3 #700

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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": "yarn@1.22.1"
}
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