From 2a82362912240a0568193b50afbe2e8f4445303f Mon Sep 17 00:00:00 2001 From: kimyenac Date: Sat, 18 Jul 2026 17:44:24 +0900 Subject: [PATCH 1/2] [ZEPPELIN-6534] Escape note name before building clone-name RegExp Cloning a note whose name contains a regex metacharacter (e.g. `[`, `(`, or a trailing backslash) threw an uncaught SyntaxError when the clone dialog opened, because the note name was interpolated into the RegExp source unescaped in cloneNoteName(). The suggested clone name was never generated and the dialog was broken for that note. Escape regex metacharacters in the note-name prefix before constructing the RegExp so any note name is matched literally. Escaping is a no-op for names without metacharacters, so clone-name numbering is unchanged. --- .../src/app/share/note-create/note-create.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts index ff0dbae759b..96f510ffd43 100644 --- a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -64,7 +64,8 @@ export class NoteCreateComponent extends MessageListenersManager implements OnIn const lastIndex = cloneNote.name.lastIndexOf(' '); const endsWithNumber = !!cloneNote.name.match('^.+?\\s\\d$'); const noteNamePrefix = endsWithNumber ? cloneNote.name.slice(0, lastIndex) : cloneNote.name; - const regexp = new RegExp(`^${noteNamePrefix}.+`); + const escapedNoteNamePrefix = noteNamePrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regexp = new RegExp(`^${escapedNoteNamePrefix}.+`); this.noteListService.notes.flatList.forEach(note => { const noteName = note.path; From 6e0448c91c0e95ad944d2276c1534774f60d342b Mon Sep 17 00:00:00 2001 From: kimyenac Date: Sat, 18 Jul 2026 17:44:24 +0900 Subject: [PATCH 2/2] [ZEPPELIN-6534] Guard onParagraphSearch against uninitialized ViewChildren Opening any note logged an uncaught "TypeError: Cannot read properties of undefined (reading 'forEach')". In ngOnInit the queryParamMap subscription runs synchronously via startWith(), calling onParagraphSearch() before the @ViewChildren QueryList (listOfNotebookParagraphComponent) is populated, which only happens after ngAfterViewInit. Guard the call with optional chaining, consistent with the existing null handling elsewhere in this component. When the paragraph components are not yet rendered there is nothing to highlight, so skipping is safe. --- .../src/app/pages/workspace/notebook/notebook.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index d76bca003e4..408ca1af281 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -272,7 +272,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit } onParagraphSearch(term: string) { - this.listOfNotebookParagraphComponent.forEach(comp => comp.highlightMatches(term || '')); + this.listOfNotebookParagraphComponent?.forEach(comp => comp.highlightMatches(term || '')); } saveParagraph(id: string) {