Add edit table of contents tool to React UI (#4917)

## Summary
- add a dedicated edit table of contents tool to the React UI, complete
with bookmark editor, import/export actions, and parameter handling
- register the tool in the translated registry and extend the English
translations with the new strings
- wire up the backend endpoints through a new operation hook and
form-data serialization helpers

## Testing
- ./gradlew build

------
[Codex
Task](https://chatgpt.com/codex/tasks/task_b_691a4a87a9c4832899ecd1c55989f27f)

---------

Co-authored-by: Reece Browne <74901996+reecebrowne@users.noreply.github.com>
This commit is contained in:
Anthony Stirling
2025-11-18 15:07:12 +00:00
committed by GitHub
parent a8ea0b60cf
commit 87bf7a5b7f
12 changed files with 1413 additions and 20 deletions

View File

@@ -0,0 +1,47 @@
export interface BookmarkPayload {
title: string;
pageNumber: number;
children?: BookmarkPayload[];
}
export interface BookmarkNode {
id: string;
title: string;
pageNumber: number;
children: BookmarkNode[];
expanded: boolean;
}
const createBookmarkId = () => {
if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
return crypto.randomUUID();
}
return `bookmark-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
};
export const createBookmarkNode = (bookmark?: Partial<BookmarkNode>): BookmarkNode => ({
id: bookmark?.id ?? createBookmarkId(),
title: bookmark?.title ?? '',
pageNumber: bookmark?.pageNumber ?? 1,
children: bookmark?.children ? bookmark.children.map(child => createBookmarkNode(child)) : [],
expanded: bookmark?.expanded ?? true,
});
export const hydrateBookmarkPayload = (payload: BookmarkPayload[] = []): BookmarkNode[] => {
return payload.map(item => ({
id: createBookmarkId(),
title: item.title ?? '',
pageNumber: typeof item.pageNumber === 'number' && item.pageNumber > 0 ? item.pageNumber : 1,
expanded: true,
children: item.children ? hydrateBookmarkPayload(item.children) : [],
}));
};
export const serializeBookmarkNodes = (bookmarks: BookmarkNode[]): BookmarkPayload[] => {
return bookmarks.map(bookmark => ({
title: bookmark.title,
pageNumber: bookmark.pageNumber,
children: serializeBookmarkNodes(bookmark.children),
}));
};