From 540b607459d071e73d89a5050e59b882e9ebc696 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Fri, 10 Apr 2026 20:13:00 +0300 Subject: [PATCH] fix(note_map): freezing the app if there are too many notes (closes #8916) --- .../src/translations/en/translation.json | 3 ++- apps/client/src/widgets/note_map/NoteMap.css | 4 ++-- apps/client/src/widgets/note_map/NoteMap.tsx | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 6006d665e4..a080456435 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -860,7 +860,8 @@ "collapse": "Collapse to normal size", "title": "Note Map", "fix-nodes": "Fix nodes", - "link-distance": "Link distance" + "link-distance": "Link distance", + "too-many-notes": "This subtree contains {{count}} notes, which exceeds the limit of {{max}} that can be displayed in the note map." }, "note_paths": { "title": "Note Paths", diff --git a/apps/client/src/widgets/note_map/NoteMap.css b/apps/client/src/widgets/note_map/NoteMap.css index fa49bb39c6..3188f09439 100644 --- a/apps/client/src/widgets/note_map/NoteMap.css +++ b/apps/client/src/widgets/note_map/NoteMap.css @@ -1,5 +1,5 @@ .note-detail-note-map { - height: 100%; + height: 100%; overflow: hidden; } @@ -54,4 +54,4 @@ width: 10px; } -/* End of styling the slider */ \ No newline at end of file +/* End of styling the slider */ diff --git a/apps/client/src/widgets/note_map/NoteMap.tsx b/apps/client/src/widgets/note_map/NoteMap.tsx index 2677e4aa59..a165d467bb 100644 --- a/apps/client/src/widgets/note_map/NoteMap.tsx +++ b/apps/client/src/widgets/note_map/NoteMap.tsx @@ -12,11 +12,15 @@ import { t } from "../../services/i18n"; import { getEffectiveThemeStyle } from "../../services/theme"; import ActionButton from "../react/ActionButton"; import { useElementSize, useNoteLabel } from "../react/hooks"; +import NoItems from "../react/NoItems"; import Slider from "../react/Slider"; import { loadNotesAndRelations, NoteMapLinkObject, NoteMapNodeObject, NotesAndRelationsData } from "./data"; import { CssData, setupRendering } from "./rendering"; import { MapType, NoteMapWidgetMode, rgb2hex } from "./utils"; +/** Maximum number of notes to render in the note map before showing a warning. */ +const MAX_NOTES_THRESHOLD = 1_000; + interface NoteMapProps { note: FNote; widgetMode: NoteMapWidgetMode; @@ -34,6 +38,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { const containerSize = useElementSize(parentRef); const [ fixNodes, setFixNodes ] = useState(false); const [ linkDistance, setLinkDistance ] = useState(40); + const [ tooManyNotes, setTooManyNotes ] = useState(null); const notesAndRelationsRef = useRef(); const mapRootId = useMemo(() => { @@ -61,6 +66,14 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { const includeRelations = labelValues("mapIncludeRelation"); loadNotesAndRelations(mapRootId, excludeRelations, includeRelations, mapType).then((notesAndRelations) => { if (!containerRef.current || !styleResolverRef.current) return; + + // Guard against rendering too many notes which would freeze the browser. + if (notesAndRelations.nodes.length > MAX_NOTES_THRESHOLD) { + setTooManyNotes(notesAndRelations.nodes.length); + return; + } + setTooManyNotes(null); + const cssData = getCssData(containerRef.current, styleResolverRef.current); // Configure rendering properties. @@ -119,6 +132,12 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) { }); }, [ fixNodes, mapType ]); + if (tooManyNotes) { + return ( + + ); + } + return (