This is an automated email from the ASF dual-hosted git repository.

chanholee pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.12 by this push:
     new 6345567505 [ZEPPELIN-6351] Close modals only on their own user actions
6345567505 is described below

commit 6345567505d20cdff4c6ad05254085b96d6c546f
Author: ChanHo Lee <[email protected]>
AuthorDate: Tue Oct 7 11:45:39 2025 +0900

    [ZEPPELIN-6351] Close modals only on their own user actions
    
    ### What is this PR for?
    On the home page, an open modal (e.g., `Import Note`, `Create New Note`) 
closes when a  `NOTES_INFO` message is received.
    
    This is unexpected and makes running parallel E2E tests that create new 
notes unreliable.
    
    #### Root cause
    Both modals treated any `NOTES_INFO` message as the result of *their* own 
submit action.
    Since `NOTES_INFO` message is broadcast for various events, this led to 
false positives.
    
    #### Fix
    Close modals only in response to messages addressed to the submitting 
client: `IMPORT_NOTE` and `NEW_NOTE`. The server already sends `NEW_NOTE` (used 
by the old UI), but not `IMPORT_NOTE`. I added a server-sent `IMPORT_NOTE` and 
replaced `broadcastNote(note)` with sending `IMPORT_NOTE` only to the caller. 
The previously broadcast `NOTE` is mainly useful to users already on that note 
page; for a newly imported note, no user is on that page yet, so the broadcast 
is unnecessary.
    
    ### What type of PR is it?
    Bug Fix
    
    ### What is the Jira issue?
    [[ZEPPELIN-6351]](https://issues.apache.org/jira/browse/ZEPPELIN-6351)
    
    ### How should this be tested?
    - Open two browser windows (A and B).
    - In A, open a modal (e.g., Import Note or Create New Note).
    - In B, perform a submit that triggers a note update. Verify the modal in A 
does not close.
    - In A, submit the modal. Verify it closes and the note list updates.
    
    ### Screenshots (if appropriate)
    
    #### [AS-IS]
    
    
https://github.com/user-attachments/assets/a38a8334-81d3-45ae-9264-755143df9041
    
    #### [TO-BE]
    
    
https://github.com/user-attachments/assets/b5e9148a-2a2a-441c-a389-aa1f558a025d
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Closes #5092 from tbonelee/fix-modal-close.
    
    Signed-off-by: ChanHo Lee <[email protected]>
    (cherry picked from commit 3ad1a2c486398a39db29dd82ff0a3e617a6e346a)
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../main/java/org/apache/zeppelin/socket/NotebookServer.java |  2 +-
 .../src/interfaces/message-data-type-map.interface.ts        |  8 ++++++--
 .../src/interfaces/message-notebook.interface.ts             | 12 ++++++++++++
 zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts    |  4 ++--
 zeppelin-web-angular/src/app/services/message.service.ts     |  3 ++-
 .../src/app/share/note-create/note-create.component.ts       |  4 ++--
 .../src/app/share/note-import/note-import.component.ts       |  8 ++++----
 .../src/components/note-import/note-import.controller.js     |  2 +-
 .../src/components/websocket/websocket-event.factory.js      |  2 ++
 9 files changed, 32 insertions(+), 13 deletions(-)

diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index d0d0af683c..5e4cccdbc4 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -1200,7 +1200,7 @@ public class NotebookServer implements 
AngularObjectRegistryListener,
           public void onSuccess(Note note, ServiceContext context) throws 
IOException {
             super.onSuccess(note, context);
             try {
-              broadcastNote(note);
+              conn.send(serializeMessage(new 
Message(OP.IMPORT_NOTE).put("note", note)));
               broadcastNoteList(context.getAutheInfo(), 
context.getUserAndRoles());
             } catch (NullPointerException e) {
               // TODO(zjffdu) remove this try catch. This is only for test of
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
index e832a1e8f9..1dd1f58c84 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
@@ -21,11 +21,14 @@ import {
   FolderRename,
   GetInterpreterBindings,
   GetNode,
+  ImportNote,
+  ImportNoteReceived,
   ListRevision,
   ListRevisionHistory,
   MoveFolderToTrash,
   MoveNoteToTrash,
   NewNote,
+  NewNoteReceived,
   Note,
   NotesInfo,
   NoteRename,
@@ -100,7 +103,8 @@ export interface MessageReceiveDataTypeMap {
   [OP.SET_NOTE_REVISION]: SetNoteRevisionStatus;
   [OP.PARAGRAPH_ADDED]: ParagraphAdded;
   [OP.NOTE_RUNNING_STATUS]: NoteRunningStatus;
-  [OP.NEW_NOTE]: NoteRevision;
+  [OP.NEW_NOTE]: NewNoteReceived;
+  [OP.IMPORT_NOTE]: ImportNoteReceived;
   [OP.SAVE_NOTE_FORMS]: SaveNoteFormsSend;
   [OP.PARAGRAPH]: UpdateParagraph;
   [OP.PATCH_PARAGRAPH]: PatchParagraphSend;
@@ -154,7 +158,7 @@ export interface MessageSendDataTypeMap {
   [OP.COMPLETION]: Completion;
   [OP.COMMIT_PARAGRAPH]: CommitParagraph;
   [OP.PATCH_PARAGRAPH]: PatchParagraphReceived;
-  [OP.IMPORT_NOTE]: {}; // TODO(hsuanxyz)
+  [OP.IMPORT_NOTE]: ImportNote;
   [OP.CHECKPOINT_NOTE]: CheckpointNote;
   [OP.SET_NOTE_REVISION]: SetNoteRevision;
   [OP.LIST_REVISION_HISTORY]: ListRevisionHistory;
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
index 24f55fecdf..f81e5c5e97 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
@@ -62,6 +62,10 @@ export interface Note {
   };
 }
 
+export interface ImportNote {
+  note: Exclude<Required<Note>['note'], 'path'>;
+}
+
 export interface NoteAngularObjects {
   // tslint:disable-next-line no-any
   [key: string]: any;
@@ -146,6 +150,14 @@ export interface NoteRunningStatus {
   status: boolean;
 }
 
+export interface NewNoteReceived {
+  note: Required<Note>['note'];
+}
+
+export interface ImportNoteReceived {
+  note: Required<Note>['note'];
+}
+
 export interface ParagraphAdded {
   index: number;
   paragraph: ParagraphItem;
diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
index 951e140bd9..0e4e8bd808 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
@@ -20,7 +20,7 @@ import {
   MessageSendDataTypeMap,
   MixMessageDataTypeMap
 } from './interfaces/message-data-type-map.interface';
-import { Note, NoteConfig, PersonalizedMode, SendNote } from 
'./interfaces/message-notebook.interface';
+import { ImportNote, Note, NoteConfig, PersonalizedMode, SendNote } from 
'./interfaces/message-notebook.interface';
 import { OP } from './interfaces/message-operator.interface';
 import {
   DynamicFormParams,
@@ -465,7 +465,7 @@ export class Message {
     });
   }
 
-  importNote(note: SendNote): void {
+  importNote(note: ImportNote['note']): void {
     this.send<OP.IMPORT_NOTE>(OP.IMPORT_NOTE, {
       note: note
     });
diff --git a/zeppelin-web-angular/src/app/services/message.service.ts 
b/zeppelin-web-angular/src/app/services/message.service.ts
index 675fc7aad1..f62697b8b6 100644
--- a/zeppelin-web-angular/src/app/services/message.service.ts
+++ b/zeppelin-web-angular/src/app/services/message.service.ts
@@ -16,6 +16,7 @@ import { Observable } from 'rxjs';
 import { MessageInterceptor, MESSAGE_INTERCEPTOR } from '@zeppelin/interfaces';
 import {
   DynamicFormParams,
+  ImportNote,
   Message,
   MessageReceiveDataTypeMap,
   MessageSendDataTypeMap,
@@ -275,7 +276,7 @@ export class MessageService extends Message implements 
OnDestroy {
     super.patchParagraph(paragraphId, noteId, patch);
   }
 
-  importNote(note: SendNote): void {
+  importNote(note: ImportNote['note']): void {
     super.importNote(note);
   }
 
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 13e1b89a52..173db41d1e 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
@@ -38,8 +38,8 @@ export class NoteCreateComponent extends 
MessageListenersManager implements OnIn
     this.cdr.markForCheck();
   }
 
-  @MessageListener(OP.NOTES_INFO)
-  getNotes(data: MessageReceiveDataTypeMap[OP.NOTES_INFO]) {
+  @MessageListener(OP.NEW_NOTE)
+  newNoteCreated(_: MessageReceiveDataTypeMap[OP.NEW_NOTE]) {
     this.nzModalRef.destroy();
   }
 
diff --git 
a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts 
b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
index f73fe7f9ec..05dc9e38d3 100644
--- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
+++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
@@ -19,7 +19,7 @@ import { NzModalRef } from 'ng-zorro-antd/modal';
 import { NzUploadFile } from 'ng-zorro-antd/upload';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
-import { MessageReceiveDataTypeMap, OP, SendNote } from '@zeppelin/sdk';
+import { ImportNote, MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk';
 
 @Component({
   selector: 'zeppelin-note-import',
@@ -34,8 +34,8 @@ export class NoteImportComponent extends 
MessageListenersManager implements OnIn
   importLoading = false;
   maxLimit = get(this.ticketService.configuration, 
['zeppelin.websocket.max.text.message.size'], null);
 
-  @MessageListener(OP.NOTES_INFO)
-  getNotes(data: MessageReceiveDataTypeMap[OP.NOTES_INFO]) {
+  @MessageListener(OP.IMPORT_NOTE)
+  noteImported(_: MessageReceiveDataTypeMap[OP.IMPORT_NOTE]) {
     this.nzModalRef.destroy();
   }
 
@@ -92,7 +92,7 @@ export class NoteImportComponent extends 
MessageListenersManager implements OnIn
         // @ts-ignore
         result.name = this.noteImportName;
       }
-      this.messageService.importNote(result as SendNote);
+      this.messageService.importNote(result as ImportNote['note']);
     } else {
       this.errorText = 'Invalid JSON';
     }
diff --git a/zeppelin-web/src/components/note-import/note-import.controller.js 
b/zeppelin-web/src/components/note-import/note-import.controller.js
index 61e21c84c7..fb14ac2edd 100644
--- a/zeppelin-web/src/components/note-import/note-import.controller.js
+++ b/zeppelin-web/src/components/note-import/note-import.controller.js
@@ -144,7 +144,7 @@ function NoteImportCtrl($scope, $timeout, websocketMsgSrv) {
    ** $scope.$on functions below
    */
 
-  $scope.$on('setNoteMenu', function(event, notes) {
+  $scope.$on('noteImported', function(event, note) {
     vm.resetFlags();
     angular.element('#noteImportModal').modal('hide');
   });
diff --git a/zeppelin-web/src/components/websocket/websocket-event.factory.js 
b/zeppelin-web/src/components/websocket/websocket-event.factory.js
index ccf941b4a3..36e94231e5 100644
--- a/zeppelin-web/src/components/websocket/websocket-event.factory.js
+++ b/zeppelin-web/src/components/websocket/websocket-event.factory.js
@@ -72,6 +72,8 @@ function WebsocketEventFactory($rootScope, $websocket, 
$location, baseUrlSrv, sa
       $rootScope.$broadcast('setNoteContent', data.note);
     } else if (op === 'NEW_NOTE') {
       $location.path('/notebook/' + data.note.id);
+    } else if (op === 'IMPORT_NOTE') {
+      $rootScope.$broadcast('noteImported', data.note);
     } else if (op === 'NOTES_INFO') {
       $rootScope.$broadcast('setNoteMenu', data.notes);
     } else if (op === 'NOTE_RUNNING_STATUS') {

Reply via email to