Skip to content

Add support for custom sidebar DocItem generators supporting customisation #963

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

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,14 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following

`sidebarOptions` can be configured with the following options:

| Name | Type | Default | Description |
| -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. |
| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). <br/><br/>`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
| Name | Type | Default | Description |
| -------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. |
| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). <br/><br/>`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object, which allows for customisation of sidebar items. For example, add a class name in certain conditions, or add `customProps` to provide custom rendering. |

> You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`.

Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-openapi-docs/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const sidebarOptions = Joi.object({
customProps: Joi.object(),
sidebarCollapsible: Joi.boolean(),
sidebarCollapsed: Joi.boolean(),
createDocItem: Joi.function(),
});

const markdownGenerators = Joi.object({
Expand Down
86 changes: 46 additions & 40 deletions packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
ProcessedSidebar,
SidebarItemCategory,
SidebarItemCategoryLinkConfig,
SidebarItemDoc,
} from "@docusaurus/plugin-content-docs/src/sidebars/types";
import { posixPath } from "@docusaurus/utils";
import clsx from "clsx";
Expand All @@ -27,6 +26,7 @@ import type {
ApiMetadata,
InfoPageMetadata,
SchemaPageMetadata,
ApiDocItemGenerator,
} from "../types";

function isApiItem(item: ApiMetadata): item is ApiMetadata {
Expand All @@ -41,6 +41,37 @@ function isSchemaItem(item: ApiMetadata): item is ApiMetadata {
return item.type === "schema";
}

const createDocItem: ApiDocItemGenerator = (
item,
{ sidebarOptions: { customProps }, basePath }
) => {
const sidebar_label = item.frontMatter.sidebar_label;
const title = item.title;
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
const className =
item.type === "api"
? clsx(
{
"menu__list-item--deprecated": item.api.deprecated,
"api-method": !!item.api.method,
},
item.api.method
)
: clsx(
{
"menu__list-item--deprecated": item.schema.deprecated,
},
"schema"
);
return {
type: "doc" as const,
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
label: (sidebar_label as string) ?? title ?? id,
customProps: customProps,
className: className ? className : undefined,
};
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method was extracted from where it was originally because it relied on basePath and customProps from higher scope. I've hoisted it and provided those via the context argument instead.


function groupByTags(
items: ApiMetadata[],
sidebarOptions: SidebarOptions,
Expand All @@ -53,12 +84,8 @@ function groupByTags(
// Remove trailing slash before proceeding
outputDir = outputDir.replace(/\/$/, "");

const {
sidebarCollapsed,
sidebarCollapsible,
customProps,
categoryLinkSource,
} = sidebarOptions;
const { sidebarCollapsed, sidebarCollapsible, categoryLinkSource } =
sidebarOptions;

const apiItems = items.filter(isApiItem) as ApiPageMetadata[];
const infoItems = items.filter(isInfoItem) as InfoPageMetadata[];
Expand Down Expand Up @@ -101,35 +128,12 @@ function groupByTags(
const basePath = docPath
? outputDir.split(docPath!)[1].replace(/^\/+/g, "")
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
function createDocItem(
item: ApiPageMetadata | SchemaPageMetadata
): SidebarItemDoc {
const sidebar_label = item.frontMatter.sidebar_label;
const title = item.title;
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
const className =
item.type === "api"
? clsx(
{
"menu__list-item--deprecated": item.api.deprecated,
"api-method": !!item.api.method,
},
item.api.method
)
: clsx(
{
"menu__list-item--deprecated": item.schema.deprecated,
},
"schema"
);
return {
type: "doc" as const,
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
label: (sidebar_label as string) ?? title ?? id,
customProps: customProps,
className: className ? className : undefined,
};
}

const createDocItemFnContext = {
sidebarOptions,
basePath,
};
const createDocItemFn = sidebarOptions.createDocItem ?? createDocItem;

let rootIntroDoc = undefined;
if (infoItems.length === 1) {
Expand Down Expand Up @@ -208,15 +212,17 @@ function groupByTags(
link: linkConfig,
collapsible: sidebarCollapsible,
collapsed: sidebarCollapsed,
items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem),
items: [...taggedSchemaItems, ...taggedApiItems].map((item) =>
createDocItemFn(item, createDocItemFnContext)
),
};
})
.filter((item) => item.items.length > 0); // Filter out any categories with no items.

// Handle items with no tag
const untaggedItems = apiItems
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
.map(createDocItem);
.map((item) => createDocItemFn(item, createDocItemFnContext));
let untagged: SidebarItemCategory[] = [];
if (untaggedItems.length > 0) {
untagged = [
Expand All @@ -227,7 +233,7 @@ function groupByTags(
collapsed: sidebarCollapsed!,
items: apiItems
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
.map(createDocItem),
.map((item) => createDocItemFn(item, createDocItemFnContext)),
},
];
}
Expand All @@ -242,7 +248,7 @@ function groupByTags(
collapsed: sidebarCollapsed!,
items: schemaItems
.filter(({ schema }) => !schema["x-tags"])
.map(createDocItem),
.map((item) => createDocItemFn(item, createDocItemFnContext)),
},
];
}
Expand Down
7 changes: 7 additions & 0 deletions packages/docusaurus-plugin-openapi-docs/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
* ========================================================================== */

import { SidebarItemDoc } from "@docusaurus/plugin-content-docs/src/sidebars/types";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that this is the right path to import types from

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it works, since our plugin aims to be 100% compatible with Docusaurus sidebars, i.e. we don't extend the SidebarItemDoc type.

import type Request from "postman-collection";

import {
Expand Down Expand Up @@ -57,12 +58,18 @@ export interface MarkdownGenerator {
createSchemaPageMD?: (pageData: SchemaPageMetadata) => string;
}

export type ApiDocItemGenerator = (
item: ApiPageMetadata | SchemaPageMetadata,
context: { sidebarOptions: SidebarOptions; basePath: string }
) => SidebarItemDoc;

export interface SidebarOptions {
groupPathsBy?: string;
categoryLinkSource?: "info" | "tag" | "auto";
customProps?: { [key: string]: unknown };
sidebarCollapsible?: boolean;
sidebarCollapsed?: boolean;
createDocItem?: ApiDocItemGenerator;
}

export interface APIVersionOptions {
Expand Down
Loading