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

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 18aaa28817 [ZEPPELIN-6632] Pass the ipynb extension without a leading 
dot when exporting a note
18aaa28817 is described below

commit 18aaa28817132deea28617e32ddcaeb7db4c67d6
Author: κΉ€λ™ν™˜ <[email protected]>
AuthorDate: Fri Oct 2 23:40:29 2026 +0900

    [ZEPPELIN-6632] Pass the ipynb extension without a leading dot when 
exporting a note
    
    ### What is this PR for?
    
    Exporting a note to ipynb from the classic UI downloads a file with two 
dots before the extension, e.g. `test sh..ipynb`.
    
    `saveAsService.saveAs()` joins the file name and the extension with a dot 
itself, and every other call site passes the extension without one (`'zpln'`, 
`'csv'`, `'tsv'`), as does the New UI's `SaveAsService`. The ipynb call site 
passes `'.ipynb'`.
    
    ZEPPELIN-4823 meant to produce `{note_name}.ipynb` and replaced 
`'zepl.ipynb'` with `'.ipynb'`, but `saveAs()` already added the dot at that 
time, so the result became `{note_name}..ipynb`.
    
    This passes `'ipynb'`, so the call site follows the same convention as the 
others.
    
    ### What type of PR is it?
    Bug Fix
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-6632
    
    ### How should this be tested?
    
    `websocket-event.factory.test.js` now replaces `saveAsService` with a spy 
and checks that a `CONVERTED_NOTE_NBFORMAT` message saves with `'ipynb'`. The 
test fails with the previous `'.ipynb'` argument.
    
    I also checked the resulting download name with the real `saveAsService` by 
capturing the anchor's `download` attribute: `test sh..ipynb` before the 
change, `test sh.ipynb` after.
    
    * zeppelin-web karma suite: 194 tests pass
    
    
    Closes #5515 from dev-donghwan/ZEPPELIN-6632.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../components/websocket/websocket-event.factory.js    |  2 +-
 .../websocket/websocket-event.factory.test.js          | 18 +++++++++++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/zeppelin-web/src/components/websocket/websocket-event.factory.js 
b/zeppelin-web/src/components/websocket/websocket-event.factory.js
index befd5b45bd..61ef7fd45c 100644
--- a/zeppelin-web/src/components/websocket/websocket-event.factory.js
+++ b/zeppelin-web/src/components/websocket/websocket-event.factory.js
@@ -202,7 +202,7 @@ function WebsocketEventFactory($rootScope, $websocket, 
$location, baseUrlSrv, sa
     } else if (op === 'PARAS_INFO') {
       $rootScope.$broadcast('updateParaInfos', data);
     } else if (op === 'CONVERTED_NOTE_NBFORMAT') {
-      saveAsService.saveAs(data.nbformat, data.noteName, '.ipynb');
+      saveAsService.saveAs(data.nbformat, data.noteName, 'ipynb');
     } else if (op === 'INTERPRETER_INSTALL_STARTED') {
       ngToast.info(data.message);
     } else if (op === 'INTERPRETER_INSTALL_RESULT') {
diff --git 
a/zeppelin-web/src/components/websocket/websocket-event.factory.test.js 
b/zeppelin-web/src/components/websocket/websocket-event.factory.test.js
index 1d95f63980..c7e9c22d8f 100644
--- a/zeppelin-web/src/components/websocket/websocket-event.factory.test.js
+++ b/zeppelin-web/src/components/websocket/websocket-event.factory.test.js
@@ -20,6 +20,7 @@ describe('Factory: websocketEvents', function() {
   let messageCallback;
   let ngToast;
   let rootScope;
+  let saveAsService;
   let websocketEvents;
 
   beforeEach(function() {
@@ -34,6 +35,7 @@ describe('Factory: websocketEvents', function() {
       socket: {readyState: 1},
     };
     ngToast = {info: jasmine.createSpy('info')};
+    saveAsService = {saveAs: jasmine.createSpy('saveAs')};
 
     angular.mock.module('zeppelinWebApp', function($provide) {
       $provide.value('$websocket', function() {
@@ -42,7 +44,7 @@ describe('Factory: websocketEvents', function() {
       $provide.value('baseUrlSrv', {getWebsocketUrl: function() {
         return 'ws://localhost/ws';
       }});
-      $provide.value('saveAsService', {saveAs: angular.noop});
+      $provide.value('saveAsService', saveAsService);
       $provide.value('ngToast', ngToast);
     });
   });
@@ -91,4 +93,18 @@ describe('Factory: websocketEvents', function() {
     expect(console.log).toHaveBeenCalledWith('Receive << %o', 'NOTICE');
     
expect(JSON.stringify(console.log.calls.allArgs())).not.toContain(payloadSecret);
   });
+
+  it('passes the ipynb extension without a leading dot when saving a converted 
note', function() {
+    const nbformat = '{"cells": []}';
+
+    messageCallback({
+      data: JSON.stringify({
+        op: 'CONVERTED_NOTE_NBFORMAT',
+        data: {nbformat: nbformat, noteName: 'test sh'},
+      }),
+    });
+
+    // saveAsService.saveAs() joins the file name and the extension with a dot 
itself
+    expect(saveAsService.saveAs).toHaveBeenCalledWith(nbformat, 'test sh', 
'ipynb');
+  });
 });

Reply via email to