From f27a7781c447f381b483c4f2ba06a7ccc6c51ab6 Mon Sep 17 00:00:00 2001 From: YONGJAE LEE Date: Wed, 3 Jun 2026 12:03:32 +0900 Subject: [PATCH] Focus paragraph editor on clone/insert in New UI --- .../pages/workspace/notebook/notebook.component.ts | 12 ++++++++++++ .../paragraph/code-editor/code-editor.component.ts | 11 ++++++++--- .../src/app/services/message.service.ts | 6 ++++++ 3 files changed, 26 insertions(+), 3 deletions(-) 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 6905a5fc4e5..a70201766d2 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 @@ -157,6 +157,18 @@ export class NotebookComponent extends MessageListenersManager implements OnInit definedNote.paragraphs[paragraphIndex].focus = true; this.cdr.markForCheck(); + + // Focus the editor only for a clone/insert initiated by this client (not auto-append on run or remote inserts). + // Defer a tick so the new paragraph's editor child exists, since `focus = true` alone misses it. + if (this.messageService.localAddFocusPending) { + this.messageService.localAddFocusPending = false; + const addedId = data.paragraph.id; + setTimeout(() => { + const added = this.listOfNotebookParagraphComponent?.find(e => e.paragraph.id === addedId); + added?.focusEditor(); + added?.notebookParagraphCodeEditorComponent?.setRestorePosition(); + }); + } } @MessageListener(OP.SAVE_NOTE_FORMS) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index c212de77cf7..6ff4c460849 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -94,19 +94,24 @@ export class NotebookParagraphCodeEditorComponent this.position = e.position; }); }), - editor.onDidChangeModelContent(() => { + editor.onDidChangeModelContent(e => { this.ngZone.run(() => { const model = editor.getModel(); if (!model) { throw new Error('Model content changed but model not found.'); } this.text = model.getValue(); - this.textChanged.emit(this.text); - this.setParagraphMode(true); this.autoAdjustEditorHeight(); setTimeout(() => { this.autoAdjustEditorHeight(); }); + // A flush is a programmatic setValue (editor init, remote content update, patch), not a user edit. + // Such changes must not mark the paragraph dirty. + if (e.isFlush) { + return; + } + this.textChanged.emit(this.text); + this.setParagraphMode(true); }); }) ); diff --git a/zeppelin-web-angular/src/app/services/message.service.ts b/zeppelin-web-angular/src/app/services/message.service.ts index 8949e5e1c79..4cf67c33817 100644 --- a/zeppelin-web-angular/src/app/services/message.service.ts +++ b/zeppelin-web-angular/src/app/services/message.service.ts @@ -38,6 +38,10 @@ import { TicketService } from './ticket.service'; providedIn: 'root' }) export class MessageService extends Message implements OnDestroy { + // Set by a local clone/insert so the PARAGRAPH_ADDED handler focuses the new + // paragraph's editor — not on auto-append or other clients' inserts. + localAddFocusPending = false; + constructor( private baseUrlService: BaseUrlService, private ticketService: TicketService, @@ -167,6 +171,7 @@ export class MessageService extends Message implements OnDestroy { } insertParagraph(newIndex: number): void { + this.localAddFocusPending = true; super.insertParagraph(newIndex); } @@ -177,6 +182,7 @@ export class MessageService extends Message implements OnDestroy { paragraphConfig: ParagraphConfig, paragraphParams: ParagraphParams ): void { + this.localAddFocusPending = true; super.copyParagraph(newIndex, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); }