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');
+ });
});