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') {