Skip to content

Commit d662e27

Browse files
committed
Add support for reusable content
1 parent 2982b6a commit d662e27

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

packages/gitbook/src/components/DocumentView/Block.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { BlockMath } from './Math';
3232
import { OpenAPI } from './OpenAPI';
3333
import { Paragraph } from './Paragraph';
3434
import { Quote } from './Quote';
35+
import { ReusableContent } from './ReusableContent';
3536
import { Stepper } from './Stepper';
3637
import { StepperStep } from './StepperStep';
3738
import { Table } from './Table';
@@ -91,7 +92,7 @@ export function Block<T extends DocumentBlock>(props: BlockProps<T>) {
9192
case 'math':
9293
return <BlockMath {...props} {...contextProps} block={block} />;
9394
case 'file':
94-
return <File {...props} {...contextProps} block={block} />;
95+
return <File {...props} {...contextProps} block={block} />
9596
case 'divider':
9697
return <Divider {...props} {...contextProps} block={block} />;
9798
case 'drawing':
@@ -107,7 +108,7 @@ export function Block<T extends DocumentBlock>(props: BlockProps<T>) {
107108
case 'synced-block':
108109
return <BlockSyncedBlock {...props} {...contextProps} block={block} />;
109110
case 'reusable-content':
110-
return null;
111+
return <ReusableContent {...props} {...contextProps} block={block} />;
111112
case 'stepper':
112113
return <Stepper {...props} {...contextProps} block={block} />;
113114
case 'stepper-step':
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { DocumentBlockReusableContent } from '@gitbook/api';
2+
3+
import { getReusableContentDocument } from '@/lib/api';
4+
5+
import { BlockProps } from './Block';
6+
import { UnwrappedBlocks } from './Blocks';
7+
8+
export async function ReusableContent(props: BlockProps<DocumentBlockReusableContent>) {
9+
const { block, context, ancestorBlocks } = props;
10+
11+
if (!context.content) {
12+
return null;
13+
}
14+
15+
const document = await getReusableContentDocument(
16+
context.content.spaceId,
17+
context.content.revisionId,
18+
block.data.ref.reusableContent,
19+
);
20+
21+
if (!document) {
22+
return null;
23+
}
24+
25+
return (
26+
<UnwrappedBlocks
27+
nodes={document.nodes}
28+
document={document}
29+
ancestorBlocks={[...ancestorBlocks, block]}
30+
context={context}
31+
/>
32+
);
33+
}

packages/gitbook/src/lib/api.ts

+64
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
GitBookAPI,
88
GitBookAPIError,
99
HttpResponse,
10+
JSONDocument,
1011
List,
1112
PublishedSiteContentLookup,
1213
RequestRenderIntegrationUI,
@@ -487,6 +488,40 @@ const getRevisionFileById = cache({
487488
},
488489
});
489490

491+
const getRevisionReusableContentById = cache({
492+
name: 'api.getRevisionReusableContentById',
493+
tag: (spaceId, revisionId) =>
494+
getAPICacheTag({ tag: 'revision', space: spaceId, revision: revisionId }),
495+
get: async (
496+
spaceId: string,
497+
revisionId: string,
498+
reusableContentId: string,
499+
options: CacheFunctionOptions,
500+
) => {
501+
try {
502+
const response = await (async () => {
503+
return api().spaces.getReusableContentInRevisionById(
504+
spaceId,
505+
revisionId,
506+
reusableContentId,
507+
{
508+
...noCacheFetchOptions,
509+
signal: options.signal,
510+
},
511+
);
512+
})();
513+
514+
return cacheResponse(response, cacheTtl_7days);
515+
} catch (error: any) {
516+
if (error instanceof GitBookAPIError && error.code === 404) {
517+
return { data: null, ...cacheTtl_7days };
518+
}
519+
520+
throw error;
521+
}
522+
},
523+
});
524+
490525
/**
491526
* Get all the files in a revision of a space.
492527
* It should not be used directly, use `getRevisionFile` instead.
@@ -578,6 +613,35 @@ export const getRevisionFile = batch<[string, string, string], RevisionFile | nu
578613
},
579614
);
580615

616+
/**
617+
* Get reusable content in a revision. Also returns the document.
618+
*/
619+
export const getReusableContentDocument = async (
620+
spaceId: string,
621+
revisionId: string,
622+
reusableContentId: string,
623+
): Promise<JSONDocument | null> => {
624+
const hasRevisionInMemory = await getRevision.hasInMemory(spaceId, revisionId, {
625+
metadata: false,
626+
});
627+
628+
if (hasRevisionInMemory) {
629+
const revision = await getRevision(spaceId, revisionId, { metadata: false });
630+
const reusableContent = revision.reusableContents[reusableContentId];
631+
if (!reusableContent) {
632+
return null;
633+
}
634+
return getDocument(reusableContent.documentId);
635+
} else {
636+
const response = await getRevisionReusableContentById(
637+
spaceId,
638+
revisionId,
639+
reusableContentId,
640+
);
641+
return response?.document ?? null;
642+
}
643+
};
644+
581645
/**
582646
* Get a document by its ID.
583647
*/

0 commit comments

Comments
 (0)