Skip to content

Commit f7f5467

Browse files
authored
Add ApiOperation component (#416)
* Add ApiOperation component Add ApiOperation component to import and display the definitions of API operations within your Docusaurus docs
1 parent 4cafbe9 commit f7f5467

File tree

7 files changed

+216
-0
lines changed

7 files changed

+216
-0
lines changed

.changeset/pretty-apples-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'docusaurus-theme-redoc': minor
3+
---
4+
5+
Add ApiOperation component to import and display the definitions of API operations within your Docusaurus docs
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { useEffect } from 'react';
2+
import clsx from 'clsx';
3+
import { ThemeProvider } from 'styled-components';
4+
import '../../global';
5+
import { Operation, OperationModel, Section } from 'redoc';
6+
import { useSpec } from '../../utils/useSpec';
7+
import { useSpecData } from '../useSpecData';
8+
import type { ApiOperationProps as Props } from '../../types/common';
9+
import '../Redoc/styles.css';
10+
import './styles.css';
11+
12+
const ApiOperation: React.FC<Props> = ({
13+
id,
14+
example,
15+
pointer,
16+
...rest
17+
}: Props): JSX.Element => {
18+
const specProps = useSpecData(id);
19+
const { store } = useSpec(specProps);
20+
21+
// The # at the start is not included
22+
const operationPointer =
23+
pointer.charAt(0) === '#' ? pointer.substring(1) : pointer;
24+
25+
// The menu contains a flattened list of spec items for easy searching
26+
const model = store.menu.flatItems.find(
27+
(item) =>
28+
item instanceof OperationModel && item.pointer === operationPointer,
29+
) as OperationModel | undefined;
30+
31+
if (!model) {
32+
throw new Error(`Failed to resolve reference "${pointer}"`);
33+
}
34+
35+
useEffect(() => {
36+
/**
37+
* @see https://github.com/Redocly/redoc/blob/823be24b313c3a2445df7e0801a0cc79c20bacd1/src/services/MenuStore.ts#L273-L276
38+
*/
39+
store.menu.dispose();
40+
}, [store]);
41+
42+
return (
43+
<ThemeProvider theme={store.options.theme}>
44+
<div
45+
className={clsx([
46+
'redocusaurus',
47+
'redocusaurus-operation',
48+
example ? null : 'hide-example',
49+
])}
50+
>
51+
<Section id={model.id} $underlined={true}>
52+
<Operation operation={model} {...rest} />
53+
</Section>
54+
</div>
55+
</ThemeProvider>
56+
);
57+
};
58+
59+
ApiOperation.defaultProps = {
60+
example: false,
61+
};
62+
63+
export default ApiOperation;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ApiOperation from './ApiOperation';
2+
3+
export default ApiOperation;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.redocusaurus-operation.hide-example > div > div > div:nth-child(2) {
2+
display: none;
3+
}
4+
.redocusaurus-operation.hide-example > div > div > div:nth-child(1) {
5+
width: 100%;
6+
}
7+
8+
.redocusaurus-operation h3 {
9+
color: var(--ifm-color-white);
10+
}
11+
12+
.redocusaurus-operation > div:last-child {
13+
min-height: 0;
14+
}

packages/docusaurus-theme-redoc/src/types/common.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ export type ApiSchemaProps = Omit<
3737
pointer: ObjectDescriptionProps['schemaRef'];
3838
};
3939

40+
export type ApiOperationProps = MdxProps & {
41+
/**
42+
* Show the example or not
43+
*/
44+
example?: boolean;
45+
46+
/**
47+
* Ref to the operation
48+
*/
49+
pointer: string;
50+
};
51+
4052
export type ApiDocProps = {
4153
specProps: SpecProps;
4254
layoutProps?: Omit<LayoutProps, 'children'>;

packages/docusaurus-theme-redoc/src/types/modules.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,29 @@ declare module '@theme/ApiSchema' {
7171
export default ApiSchema;
7272
}
7373

74+
declare module '@theme/ApiOperation' {
75+
interface ApiOperationProps {
76+
/**
77+
* If you have multiple apis, then add a `id` field in the specs array
78+
* And pass the same here
79+
*/
80+
id?: string;
81+
82+
/**
83+
* Show the example or not
84+
*/
85+
example?: boolean;
86+
87+
/**
88+
* Ref to the operation
89+
*/
90+
pointer: string;
91+
}
92+
93+
const ApiOperation: (props: ApiOperationProps) => JSX.Element;
94+
export default ApiOperation;
95+
}
96+
7497
declare module '@theme/useSpecData' {
7598
/**
7699
* Load redocusaurus plugin data by ID
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
title: Operation Imports
3+
sidebar_position: 1.5
4+
---
5+
6+
import ApiOperation from '@theme/ApiOperation';
7+
8+
# Operation Imports
9+
10+
You can import operation definitions from your API schema and render them in your Docusaurus Docs. You'll need to create an `.mdx` file and import the React Component. Read more [here about MDX in Docusaurus](https://docusaurus.io/docs/markdown-features/react).
11+
12+
# Import Operation Model in Docs
13+
14+
The `pointer` prop is passed on to [Redoc](https://redoc.ly/docs/resources/ref-guide/#pointer).
15+
16+
Note that `/` is escaped as `~1`.
17+
18+
```tsx
19+
import ApiOperation from '@theme/ApiOperation';
20+
21+
<ApiOperation pointer="#/paths/~1pet/post" />;
22+
```
23+
24+
### Results
25+
26+
<ApiOperation pointer="#/paths/~1pet/post" />
27+
28+
## Import Operation Model (with example) in Docs
29+
30+
```tsx
31+
import ApiOperation from '@theme/ApiOperation';
32+
33+
<ApiOperation example pointer="#/paths/~1pet/post" />;
34+
```
35+
36+
### Results
37+
38+
<ApiOperation example pointer="#/paths/~1pet/post" />
39+
40+
## Importing Operation Model with multiple OpenAPI schemas
41+
42+
If you have multiple APIs loaded with redocusaurus, then it is recommended to add `id`s to the config so that you can refer them when loading operation models.
43+
44+
```js title="docusaurus.config.js"
45+
const config = {
46+
presets: [
47+
'@docusaurus/preset-classic',
48+
[
49+
'redocusaurus',
50+
{
51+
specs: [
52+
{
53+
id: 'using-single-yaml',
54+
spec: 'openapi/single-file/openapi.yaml',
55+
route: '/examples/using-single-yaml/',
56+
},
57+
{
58+
id: 'using-remote-url',
59+
spec: 'https://redocly.github.io/redoc/openapi.yaml',
60+
route: '/examples/using-remote-url/',
61+
},
62+
],
63+
theme: {
64+
/**
65+
* Highlight color for docs
66+
*/
67+
primaryColor: '#1890ff',
68+
/**
69+
* Options to pass to redoc
70+
* @see https://github.com/redocly/redoc#redoc-options-object
71+
*/
72+
options: { disableSearch: true },
73+
},
74+
},
75+
],
76+
],
77+
title: 'Redocusaurus',
78+
};
79+
```
80+
81+
```tsx
82+
import ApiOperation from '@theme/ApiOperation';
83+
84+
<ApiOperation id="using-single-yaml" pointer="#/paths/~1pet/post" />
85+
<ApiOperation id="using-remote-url" pointer="#/paths/~1pet/post" />
86+
```
87+
88+
### Results
89+
90+
#### For ID `id="using-single-yaml"`
91+
92+
<ApiOperation id="using-single-yaml" pointer="#/paths/~1pet/post" />
93+
94+
#### For ID `id="using-remote-url"`
95+
96+
<ApiOperation id="using-remote-url" pointer="#/paths/~1pet/post" />

0 commit comments

Comments
 (0)