️(frontend) fetch document without content when not needed

To improve performance, especially for documents
with large content, an optional query parameter
`without_content` has been added to the document
fetching API endpoint. When this parameter is set
to true, the API will return the document
metadata without the content, allowing the frontend
to load faster and reduce unnecessary data transfer.
This commit is contained in:
Anthony LC
2026-02-24 11:14:12 +01:00
committed by Manuel Raynaud
parent ffae927c93
commit 1ac6b42ae3
7 changed files with 26 additions and 14 deletions

View File

@@ -95,7 +95,7 @@ export const LinkSelected = ({
isEditable,
updateInlineContent,
}: LinkSelectedProps) => {
const { data: doc } = useDoc({ id: docId });
const { data: doc } = useDoc({ id: docId, withoutContent: true });
/**
* Update the content title if the referenced doc title changes

View File

@@ -6,10 +6,15 @@ import { Doc } from '../types';
export type DocParams = {
id: string;
withoutContent?: boolean;
};
export const getDoc = async ({ id }: DocParams): Promise<Doc> => {
const response = await fetchAPI(`documents/${id}/`);
export const getDoc = async ({
id,
withoutContent,
}: DocParams): Promise<Doc> => {
const params = withoutContent ? '?without_content=true' : '';
const response = await fetchAPI(`documents/${id}/${params}`);
if (!response.ok) {
throw new APIError('Failed to get the doc', await errorCauses(response));

View File

@@ -53,7 +53,7 @@ export interface Doc {
title?: string;
children?: Doc[];
childrenCount?: number;
content: Base64;
content?: Base64;
created_at: string;
creator: string;
deleted_at: string | null;

View File

@@ -19,10 +19,13 @@ describe('CollaborationBackend', () => {
const { fetchDocument } = await import('@/api/collaborationBackend');
const documentId = 'test-document-123';
await fetchDocument(documentId, { cookie: 'test-cookie' });
await fetchDocument(
{ name: documentId, withoutContent: true },
{ cookie: 'test-cookie' },
);
expect(axiosGetSpy).toHaveBeenCalledWith(
`http://app-dev:8000/api/v1.0/documents/${documentId}/`,
`http://app-dev:8000/api/v1.0/documents/${documentId}/?without_content=true`,
expect.objectContaining({
headers: expect.objectContaining({
'X-Y-Provider-Key': 'test-yprovider-key',

View File

@@ -228,7 +228,7 @@ describe('Server Tests', () => {
wsHocus.stopConnectionAttempt();
expect(data.reason).toBe('permission-denied');
expect(fetchDocumentMock).toHaveBeenCalledExactlyOnceWith(
room,
{ name: room, withoutContent: true },
expect.any(Object),
);
wsHocus.webSocket?.close();
@@ -273,7 +273,7 @@ describe('Server Tests', () => {
wsHocus.stopConnectionAttempt();
expect(data.reason).toBe('permission-denied');
expect(fetchDocumentMock).toHaveBeenCalledExactlyOnceWith(
room,
{ name: room, withoutContent: true },
expect.any(Object),
);
wsHocus.webSocket?.close();
@@ -322,7 +322,7 @@ describe('Server Tests', () => {
wsHocus.destroy();
expect(fetchDocumentMock).toHaveBeenCalledWith(
room,
{ name: room, withoutContent: true },
expect.any(Object),
);
@@ -371,7 +371,7 @@ describe('Server Tests', () => {
wsHocus.destroy();
expect(fetchDocumentMock).toHaveBeenCalledWith(
room,
{ name: room, withoutContent: true },
expect.any(Object),
);

View File

@@ -17,7 +17,7 @@ type Base64 = string;
interface Doc {
id: string;
title?: string;
content: Base64;
content?: Base64;
creator: string;
is_favorite: boolean;
link_reach: 'restricted' | 'public' | 'authenticated';
@@ -74,10 +74,11 @@ async function fetch<T>(
}
export function fetchDocument(
name: string,
{ name, withoutContent }: { name: string; withoutContent?: boolean },
requestHeaders: IncomingHttpHeaders,
): Promise<Doc> {
return fetch<Doc>(`/api/v1.0/documents/${name}/`, requestHeaders);
const params = withoutContent ? '?without_content=true' : '';
return fetch<Doc>(`/api/v1.0/documents/${name}/${params}`, requestHeaders);
}
export function fetchCurrentUser(

View File

@@ -39,7 +39,10 @@ export const hocuspocusServer = new Server({
let canEdit;
try {
const document = await fetchDocument(documentName, requestHeaders);
const document = await fetchDocument(
{ name: documentName, withoutContent: true },
requestHeaders,
);
if (!document.abilities.retrieve) {
logger(