Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 4D9B9200CF3 for ; Tue, 15 Aug 2017 00:36:27 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 4C230165F87; Mon, 14 Aug 2017 22:36:27 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 45E3B165F86 for ; Tue, 15 Aug 2017 00:36:26 +0200 (CEST) Received: (qmail 15516 invoked by uid 500); 14 Aug 2017 22:36:25 -0000 Mailing-List: contact commits-help@zeppelin.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zeppelin.apache.org Delivered-To: mailing list commits@zeppelin.apache.org Received: (qmail 15506 invoked by uid 99); 14 Aug 2017 22:36:25 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 14 Aug 2017 22:36:25 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 100E4E964C; Mon, 14 Aug 2017 22:36:25 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: prabhjyotsingh@apache.org To: commits@zeppelin.apache.org Message-Id: <333113dc5fca42b292f8a834f0048d01@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: zeppelin git commit: [ZEPPELIN-2823] Notebook saved status is wrong if there was a network disconnect or a flaky network. Date: Mon, 14 Aug 2017 22:36:25 +0000 (UTC) archived-at: Mon, 14 Aug 2017 22:36:27 -0000 Repository: zeppelin Updated Branches: refs/heads/master 71d130521 -> 340b326d4 [ZEPPELIN-2823] Notebook saved status is wrong if there was a network disconnect or a flaky network. ### What is this PR for? Notebook content doesn't get saved if there is a flaky network, and at times user's paragraph content also gets lost in this process. ### What type of PR is it? [Bug Fix] ### What is the Jira issue? * [ZEPPELIN-2823](https://issues.apache.org/jira/browse/ZEPPELIN-2823) ### How should this be tested? Steps to re-produce: - create a new notebook - in the first paragraph enter text, say "version1" - now disconnect the network (say by removing LAN cable) - update this paragraph again with text "version2" - reconnect network - now observe the on the WebSocket reconnect, the content of this paragraph will go back to "version1" ### Screenshots (if appropriate) Before ![before](https://user-images.githubusercontent.com/674497/28852738-5772029e-76e0-11e7-82ed-8c2a25d3ab47.gif) After ![after](https://user-images.githubusercontent.com/674497/28852739-5774efcc-76e0-11e7-9e48-4bda935c4686.gif) ### Questions: * Does the licenses files need an update? N/A * Is there breaking changes for older versions? N/A * Does this needs documentation? N/A Author: Prabhjyot Singh Closes #2512 from prabhjyotsingh/ZEPPELIN-2823 and squashes the following commits: 5f693ab93 [Prabhjyot Singh] - replace _.forEach with .map - extract BootstrapDialog.show outside of the for loop db30f479b [Prabhjyot Singh] alter text to `Changes that you have made will not be saved` 947be70b4 [Prabhjyot Singh] check if noteId exists in session or take it from fromMessage 8b8c2f974 [Prabhjyot Singh] check for empty originalText d2a835f77 [Prabhjyot Singh] wait for server confirmation before updating stats of notebook Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/340b326d Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/340b326d Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/340b326d Branch: refs/heads/master Commit: 340b326d47f3e07b7d98c2760b41c10424bfbb30 Parents: 71d1305 Author: Prabhjyot Singh Authored: Thu Aug 10 15:24:17 2017 -0700 Committer: Prabhjyot Singh Committed: Mon Aug 14 15:36:16 2017 -0700 ---------------------------------------------------------------------- .../apache/zeppelin/socket/NotebookServer.java | 3 + .../src/app/notebook/notebook.controller.js | 60 ++++++++++++++++++-- .../notebook/paragraph/paragraph.controller.js | 36 ++++++++++-- .../paragraph/result/result.controller.js | 2 +- .../websocket/websocket-event.factory.js | 2 +- .../websocket/websocket-message.service.js | 5 +- 6 files changed, 95 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java ---------------------------------------------------------------------- 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 61bc536..3ddeec0 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 @@ -1186,6 +1186,9 @@ public class NotebookServer extends WebSocketServlet Map params = (Map) fromMessage.get("params"); Map config = (Map) fromMessage.get("config"); String noteId = getOpenNoteId(conn); + if (noteId == null) { + noteId = (String) fromMessage.get("noteId"); + } if (!hasParagraphWriterPermission(conn, notebook, noteId, userAndRoles, fromMessage.principal, "write")) { http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-web/src/app/notebook/notebook.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index a51ad4f..4b8b23f 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -51,6 +51,7 @@ function NotebookCtrl ($scope, $route, $routeParams, $location, $rootScope, $scope.interpreterBindings = [] $scope.isNoteDirty = null $scope.saveTimer = null + $scope.paragraphWarningDialog = {} let connectedOnce = false let isRevisionPath = function (path) { @@ -396,11 +397,6 @@ function NotebookCtrl ($scope, $route, $routeParams, $location, $rootScope, }, 10000) } - angular.element(window).on('beforeunload', function (e) { - $scope.killSaveTimer() - $scope.saveNote() - }) - $scope.setLookAndFeel = function (looknfeel) { $scope.note.config.looknfeel = looknfeel if ($scope.revisionView === true) { @@ -1277,6 +1273,60 @@ function NotebookCtrl ($scope, $route, $routeParams, $location, $rootScope, $scope.note.config.personalizedMode = isPersonalized }) + $scope.$on('$routeChangeStart', function (event, next, current) { + if (!$scope.note || !$scope.note.paragraphs) { + return + } + if ($scope.note && $scope.note.paragraphs) { + $scope.note.paragraphs.map(par => { + if ($scope.allowLeave === true) { + return + } + let thisScope = angular.element( + '#' + par.id + '_paragraphColumn_main').scope() + + if (thisScope.dirtyText === undefined || + thisScope.originalText === undefined || + thisScope.dirtyText === thisScope.originalText) { + return true + } else { + event.preventDefault() + $scope.showParagraphWarning(next) + } + }) + } + }) + + $scope.showParagraphWarning = function (next) { + if ($scope.paragraphWarningDialog.opened !== true) { + $scope.paragraphWarningDialog = BootstrapDialog.show({ + closable: false, + closeByBackdrop: false, + closeByKeyboard: false, + title: 'Do you want to leave this site?', + message: 'Changes that you have made will not be saved.', + buttons: [{ + label: 'Stay', + action: function (dialog) { + dialog.close() + } + }, { + label: 'Leave', + action: function (dialog) { + dialog.close() + let locationToRedirect = next['$$route']['originalPath'] + Object.keys(next.pathParams).map(key => { + locationToRedirect = locationToRedirect.replace(':' + key, + next.pathParams[key]) + }) + $scope.allowLeave = true + $location.path(locationToRedirect) + } + }] + }) + } + } + $scope.$on('$destroy', function () { angular.element(window).off('beforeunload') $scope.killSaveTimer() http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js index 141f7b3..b4c79dd 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js @@ -382,14 +382,41 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca paragraphText, $scope.paragraph.config, $scope.paragraph.settings.params) } + $scope.bindBeforeUnload = function () { + angular.element(window).off('beforeunload') + + let confirmOnPageExit = function (e) { + // If we haven't been passed the event get the window.event + e = e || window.event + let message = 'Do you want to reload this site?' + + // For IE6-8 and Firefox prior to version 4 + if (e) { + e.returnValue = message + } + // For Chrome, Safari, IE8+ and Opera 12+ + return message + } + angular.element(window).on('beforeunload', confirmOnPageExit) + } + + $scope.unBindBeforeUnload = function () { + angular.element(window).off('beforeunload') + } + $scope.saveParagraph = function (paragraph) { const dirtyText = paragraph.text if (dirtyText === undefined || dirtyText === $scope.originalText) { return } - commitParagraph(paragraph) - $scope.originalText = dirtyText - $scope.dirtyText = undefined + + $scope.bindBeforeUnload() + + commitParagraph(paragraph).then(function () { + $scope.originalText = dirtyText + $scope.dirtyText = undefined + $scope.unBindBeforeUnload() + }) } $scope.toggleEnableDisable = function (paragraph) { @@ -1092,7 +1119,8 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca settings: {params}, } = paragraph - websocketMsgSrv.commitParagraph(id, title, text, config, params) + return websocketMsgSrv.commitParagraph(id, title, text, config, params, + $route.current.pathParams.noteId) } /** Utility function */ http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js index df9ebe9..be71d9c 100644 --- a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js +++ b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js @@ -645,7 +645,7 @@ function ResultCtrl ($scope, $rootScope, $route, $window, $routeParams, $locatio }, newParagraphConfig.results[resultIndex], paragraph, resultIndex) renderResult($scope.type, true) } else { - websocketMsgSrv.commitParagraph(paragraph.id, title, text, newParagraphConfig, params) + return websocketMsgSrv.commitParagraph(paragraph.id, title, text, newParagraphConfig, params) } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-web/src/components/websocket/websocket-event.factory.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/websocket/websocket-event.factory.js b/zeppelin-web/src/components/websocket/websocket-event.factory.js index db058bb..10cfd9c 100644 --- a/zeppelin-web/src/components/websocket/websocket-event.factory.js +++ b/zeppelin-web/src/components/websocket/websocket-event.factory.js @@ -42,7 +42,7 @@ function WebsocketEventFactory ($rootScope, $websocket, $location, baseUrlSrv) { data.roles = '' } console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data) - websocketCalls.ws.send(JSON.stringify(data)) + return websocketCalls.ws.send(JSON.stringify(data)) } websocketCalls.isConnected = function () { http://git-wip-us.apache.org/repos/asf/zeppelin/blob/340b326d/zeppelin-web/src/components/websocket/websocket-message.service.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/websocket/websocket-message.service.js b/zeppelin-web/src/components/websocket/websocket-message.service.js index 0dc02c3..cafc61b 100644 --- a/zeppelin-web/src/components/websocket/websocket-message.service.js +++ b/zeppelin-web/src/components/websocket/websocket-message.service.js @@ -233,11 +233,12 @@ function WebsocketMessageService ($rootScope, websocketEvents) { }) }, - commitParagraph: function (paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) { - websocketEvents.sendNewEvent({ + commitParagraph: function (paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams, noteId) { + return websocketEvents.sendNewEvent({ op: 'COMMIT_PARAGRAPH', data: { id: paragraphId, + noteId: noteId, title: paragraphTitle, paragraph: paragraphData, config: paragraphConfig,