Repository: zeppelin
Updated Branches:
  refs/heads/master daceee568 -> 5cdc02d36


[Zeppelin - 1152] Listing note revision history

### What is this PR for?
This PR addresses ability to view the history of note revisions from the 
`version control` menu

### What type of PR is it?
Improvement

### Todos
* [x] - backend changes
* [x] - tests
* [x] - propagation to frontend
* [x] -  rendering list

### What is the Jira issue?
[Zeppelin - 1152](https://issues.apache.org/jira/browse/ZEPPELIN-1152)

### How should this be tested?
1. Select Git notebook storage layer as primary (e.g. in `conf/zeppelin-env.sh` 
add
```
export 
ZEPPELIN_NOTEBOOK_STORAGE="org.apache.zeppelin.notebook.repo.GitNotebookRepo"
```
2. Select any note in Zeppelin and `commit` it in `version control` menu
3. The list with new commit should be shown in the same menu

### Screenshots (if appropriate)
<img width="782" alt="screen shot 2016-07-21 at 11 35 21 am" 
src="https://cloud.githubusercontent.com/assets/1642088/17009639/c8bcbd58-4f37-11e6-92cd-88147b7419e6.png";>

### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No

Author: Khalid Huseynov <[email protected]>
Author: Khalid Huseynov <[email protected]>
Author: Damien CORNEAU <[email protected]>

Closes #1160 from khalidhuseynov/front/list-revision-history and squashes the 
following commits:

924a6c5 [Khalid Huseynov] address @corneadoug comments
614ed61 [Khalid Huseynov] date: smaller font and spacing
f676b74 [Khalid Huseynov] Merge branch 'master' into front/list-revision-history
bd068fd [Khalid Huseynov] add css class with smaller font for revision date
0445b42 [Khalid Huseynov] move date to right, add time
4607c03 [Khalid Huseynov] fix css
e6bafde [Khalid Huseynov] change time format
2090d60 [Khalid Huseynov] mock listRevisionHistory
1d20aeb [Khalid Huseynov] fix jshint checkstyle
ee7b94f [Damien CORNEAU] Reverse revisions order to have the latest first
9523b48 [Damien CORNEAU] Add dropdown of revisions
660139b [Damien CORNEAU] fix the jscs error
bcf6cf1 [Khalid Huseynov] return list on successful commit
18d430a [Khalid Huseynov] add initial listing
b4c69df [Khalid Huseynov] add test: revision history, multiple notes
d8f4282 [Khalid Huseynov] add new note resource for tests with multiple notes
a7e8fd8 [Khalid Huseynov] initial impl


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/5cdc02d3
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/5cdc02d3
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/5cdc02d3

Branch: refs/heads/master
Commit: 5cdc02d3651fc8f5b7f9aa81f1d617007932b666
Parents: daceee5
Author: Khalid Huseynov <[email protected]>
Authored: Thu Jul 21 11:32:01 2016 +0900
Committer: Alexander Bezzubov <[email protected]>
Committed: Thu Jul 21 20:22:30 2016 +0900

----------------------------------------------------------------------
 .../apache/zeppelin/socket/NotebookServer.java  | 21 ++++-
 .../src/app/notebook/notebook-actionBar.html    | 83 +++++++++++++------
 .../src/app/notebook/notebook.controller.js     | 15 ++++
 zeppelin-web/src/app/notebook/notebook.css      | 42 ++++++++++
 .../websocketEvents/websocketEvents.factory.js  |  2 +
 .../websocketEvents/websocketMsg.service.js     |  9 ++
 zeppelin-web/test/spec/controllers/notebook.js  |  3 +-
 .../org/apache/zeppelin/notebook/Notebook.java  | 11 ++-
 .../notebook/repo/NotebookRepoSync.java         | 10 ++-
 .../zeppelin/notebook/socket/Message.java       |  3 +
 .../notebook/repo/GitNotebookRepoTest.java      | 55 ++++++++++++-
 .../src/test/resources/2A94M5J2Z/note.json      | 87 ++++++++++++++++++++
 12 files changed, 303 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/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 1859ba0..0f8ce70 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
@@ -45,6 +45,7 @@ import org.apache.zeppelin.interpreter.InterpreterResult;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
 import org.apache.zeppelin.notebook.*;
+import org.apache.zeppelin.notebook.repo.NotebookRepo;
 import org.apache.zeppelin.notebook.repo.NotebookRepo.Revision;
 import org.apache.zeppelin.notebook.socket.Message;
 import org.apache.zeppelin.notebook.socket.Message.OP;
@@ -221,6 +222,9 @@ public class NotebookServer extends WebSocketServlet 
implements
           case CHECKPOINT_NOTEBOOK:
             checkpointNotebook(conn, notebook, messagereceived);
             break;
+          case LIST_REVISION_HISTORY:
+            listRevisionHistory(conn, notebook, messagereceived);
+            break;
           case NOTE_REVISION:
             getNoteRevision(conn, notebook, messagereceived);
             break;
@@ -1130,7 +1134,22 @@ public class NotebookServer extends WebSocketServlet 
implements
     String noteId = (String) fromMessage.get("noteId");
     String commitMessage = (String) fromMessage.get("commitMessage");
     AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal);
-    notebook.checkpointNote(noteId, commitMessage, subject);
+    Revision revision = notebook.checkpointNote(noteId, commitMessage, 
subject);
+    if (revision != null) {
+      List<NotebookRepo.Revision> revisions = 
notebook.listRevisionHistory(noteId, subject);
+      conn.send(serializeMessage(new Message(OP.LIST_REVISION_HISTORY)
+        .put("revisionList", revisions)));
+    }
+  }
+
+  private void listRevisionHistory(NotebookSocket conn, Notebook notebook,
+      Message fromMessage) throws IOException {
+    String noteId = (String) fromMessage.get("noteId");
+    AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal);
+    List<NotebookRepo.Revision> revisions = 
notebook.listRevisionHistory(noteId, subject);
+
+    conn.send(serializeMessage(new Message(OP.LIST_REVISION_HISTORY)
+      .put("revisionList", revisions)));
   }
 
   private void getNoteRevision(NotebookSocket conn, Notebook notebook, Message 
fromMessage)

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-web/src/app/notebook/notebook-actionBar.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html 
b/zeppelin-web/src/app/notebook/notebook-actionBar.html
index 170d56d..cf13d50 100644
--- a/zeppelin-web/src/app/notebook/notebook-actionBar.html
+++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html
@@ -64,34 +64,63 @@ limitations under the License.
               tooltip-placement="bottom" tooltip="Export the notebook">
         <i class="fa fa-download"></i>
       </button>
-      <button type="button"
-              class="btn btn-default btn-xs dropdown-toggle"
-              ng-hide="viewOnly"
-              data-toggle="dropdown"
-              tooltip-placement="bottom" tooltip="Version control">
-        <i class="fa fa-file-code-o"></i>
-      </button>
-      <ul class="dropdown-menu" role="menu" style="width:250px">
-        <li>
-          <div class="commit-container">
-            <div>
-              <input type="text"
-                     dropdown-input
-                     placeholder="commit message"
-                     id="note.checkpoint.message"
-                     style="width: 145px;"
-                     ng-model="note.checkpoint.message"/>
-              <button type="button"
-                      class="btn btn-default btn-xs"
-                      ng-hide="viewOnly"
-                      ng-click="checkpointNotebook(note.checkpoint.message)"
-                      style="margin-left: 4px;"
-                      tooltip-placement="bottom" tooltip="Commit the 
notebook">Commit
-              </button>
+    </span>
+
+    <span class="labelBtn btn-group" role="group">
+      <div class="btn-group" role="group">
+        <button type="button"
+                class="btn btn-default btn-xs dropdown-toggle"
+                id="versionControlDropdown"
+                ng-hide="viewOnly"
+                data-toggle="dropdown"
+                tooltip-placement="bottom" tooltip="Version control">
+          <i class="fa fa-file-code-o"></i>
+        </button>
+        <ul class="dropdown-menu" style="width:250px"
+          aria-labelledby="versionControlDropdown">
+          <li>
+            <div class="commit-container">
+              <div>
+                <input type="text"
+                       dropdown-input
+                       placeholder="commit message"
+                       id="note.checkpoint.message"
+                       style="width: 145px;"
+                       ng-model="note.checkpoint.message"/>
+                <button type="button"
+                        class="btn btn-default btn-xs"
+                        ng-hide="viewOnly"
+                        ng-click="checkpointNotebook(note.checkpoint.message)"
+                        style="margin-left: 4px;"
+                        tooltip-placement="bottom" tooltip="Commit the 
notebook">Commit
+                </button>
+              </div>
             </div>
-          </div>
-        </li>
-      </ul>
+          </li>
+        </ul>
+      </div>
+      <div class="btn-group" role="group">
+        <button type="button" class="btn btn-default btn-xs revisionName">
+          Head
+        </button>
+        <button type="button" ng-if="noteRevisions.length > 0"
+          class="btn btn-default dropdown-toggle caretSeparator"
+          data-toggle="dropdown" id="revisionsDropdown">
+          <span class="caret"></span>
+        </button>
+        <ul class="dropdown-menu pull-right" 
aria-labelledby="revisionsDropdown">
+          <li ng-repeat="revision in noteRevisions | orderBy:'time':true" 
class="revision">
+            <a style="cursor:pointer">
+              <span style="display: block;">
+                <strong>{{revision.message}}</strong>
+              </span>
+              <span class="revisionDate">
+                <em>{{moment.unix(revision.time).format('MMMM Do YYYY, h:mm 
a')}}</em>
+              </span>
+            </a>
+          </li>
+        </ul>
+      </div>
     </span>
 
 <!-- put the delete action by itself for your protection -->

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/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 81b9c32..dc59f50 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -17,6 +17,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', 
function($scope, $ro
                                                                      
$rootScope, $http, websocketMsgSrv,
                                                                      
baseUrlSrv, $timeout, saveAsService) {
   $scope.note = null;
+  $scope.moment = moment;
   $scope.showEditor = false;
   $scope.editorToggled = false;
   $scope.tableToggled = false;
@@ -52,6 +53,14 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', 
function($scope, $ro
   var previousSelectedListWriters = [];
   var searchText = [];
   $scope.role = '';
+  $scope.noteRevisions = [];
+
+  $scope.$on('setConnectedStatus', function(event, param) {
+    if (connectedOnce && param) {
+      initNotebook();
+    }
+    connectedOnce = true;
+  });
 
   $scope.getCronOptionNameFromValue = function(value) {
     if (!value) {
@@ -69,6 +78,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', 
function($scope, $ro
   /** Init the new controller */
   var initNotebook = function() {
     websocketMsgSrv.getNotebook($routeParams.noteId);
+    websocketMsgSrv.listRevisionHistory($routeParams.noteId);
 
     var currentRoute = $route.current;
     if (currentRoute) {
@@ -173,6 +183,11 @@ 
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
     document.getElementById('note.checkpoint.message').value = '';
   };
 
+  $scope.$on('listRevisionHistory', function(event, data) {
+    console.log('We got the revisions %o', data);
+    $scope.noteRevisions = data.revisionList;
+  });
+
   // receive certain revision of note
   $scope.$on('noteRevision', function(event, data) {
     console.log('received note revision %o', data);

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-web/src/app/notebook/notebook.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.css 
b/zeppelin-web/src/app/notebook/notebook.css
index 59f7561..ed45c67 100644
--- a/zeppelin-web/src/app/notebook/notebook.css
+++ b/zeppelin-web/src/app/notebook/notebook.css
@@ -16,6 +16,48 @@
   padding-top: 36px;
 }
 
+.revision  {
+  max-width: 250px;
+  margin-bottom: 0 !important;
+}
+
+.revision a {
+  padding: 2px 10px !important;
+}
+
+.revision a span {
+  width: 100%;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.revisionName {
+  cursor: default;
+  padding: 1px 10px !important;
+  max-width: 150px;
+}
+
+.revisionDate {
+  font-size: 8px;
+  color: DarkGrey;
+  display: block;
+}
+
+.revisionName:hover,
+.revisionName:focus,
+.revisionName:active {
+  background: transparent;
+  border-color: #ccc;
+}
+
+.caretSeparator {
+  height: 22px;
+  line-height: 9px;
+  width: 16px;
+  padding-left: 3px !important;
+}
+
 .paragraph-col {
   margin: 0;
   padding: 0;

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
----------------------------------------------------------------------
diff --git 
a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js 
b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
index 6c9eeee..7657137 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
@@ -109,6 +109,8 @@ angular.module('zeppelinWebApp').factory('websocketEvents',
       $rootScope.$broadcast('appLoad', data);
     } else if (op === 'APP_STATUS_CHANGE') {
       $rootScope.$broadcast('appStatusChange', data);
+    } else if (op === 'LIST_REVISION_HISTORY') {
+      $rootScope.$broadcast('listRevisionHistory', data);
     } else if (op === 'NOTE_REVISION') {
       $rootScope.$broadcast('noteRevision', data);
     }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
----------------------------------------------------------------------
diff --git 
a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js 
b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
index 9a82c9b..a4f7802 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
@@ -161,6 +161,15 @@ 
angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
       });
     },
 
+    listRevisionHistory: function(noteId) {
+      websocketEvents.sendNewEvent({
+        op: 'LIST_REVISION_HISTORY',
+        data: {
+          noteId: noteId
+        }
+      });
+    },
+
     getNoteRevision: function(noteId, revisionId) {
       websocketEvents.sendNewEvent({
         op: 'NOTE_REVISION',

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-web/test/spec/controllers/notebook.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/test/spec/controllers/notebook.js 
b/zeppelin-web/test/spec/controllers/notebook.js
index 77ddfff..d9b35b1 100644
--- a/zeppelin-web/test/spec/controllers/notebook.js
+++ b/zeppelin-web/test/spec/controllers/notebook.js
@@ -6,7 +6,8 @@ describe('Controller: NotebookCtrl', function() {
   var scope;
 
   var websocketMsgSrvMock = {
-    getNotebook: function() {}
+    getNotebook: function() {},
+    listRevisionHistory: function() {}
   };
 
   var baseUrlSrvMock = {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
index 9937d61..3620464 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java
@@ -353,9 +353,14 @@ public class Notebook implements NoteEventListener {
     }
   }
 
-  public void checkpointNote(String noteId, String checkpointMessage, 
AuthenticationInfo subject)
-      throws IOException {
-    notebookRepo.checkpoint(noteId, checkpointMessage, subject);
+  public Revision checkpointNote(String noteId, String checkpointMessage,
+      AuthenticationInfo subject) throws IOException {
+    return notebookRepo.checkpoint(noteId, checkpointMessage, subject);
+  }
+
+  public List<NotebookRepo.Revision> listRevisionHistory(String noteId,
+      AuthenticationInfo subject) {
+    return notebookRepo.revisionHistory(noteId, subject);
   }
 
   public Note getNoteRevision(String noteId, Revision revision, 
AuthenticationInfo subject)

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
index 4e735e8..6c499c6 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -366,7 +367,12 @@ public class NotebookRepoSync implements NotebookRepo {
 
   @Override
   public List<Revision> revisionHistory(String noteId, AuthenticationInfo 
subject) {
-    // Auto-generated method stub
-    return null;
+    List<Revision> revisions = Collections.emptyList();
+    try {
+      revisions = getRepo(0).revisionHistory(noteId, subject);
+    } catch (IOException e) {
+      LOG.error("Failed to list revision history", e);
+    }
+    return revisions;
   }
 }

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
index c0baf40..e2f5fe9 100644
--- 
a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
+++ 
b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
@@ -114,6 +114,9 @@ public class Message {
     CHECKPOINT_NOTEBOOK,    // [c-s] checkpoint notebook to storage repository
                             // @param noteId
                             // @param checkpointName
+
+    LIST_REVISION_HISTORY,  // [c-s] list revision history of the notebook
+                            // @param noteId
     NOTE_REVISION,          // [c-s] get certain revision of note
                             // @param noteId
                             // @param revisionId

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java
----------------------------------------------------------------------
diff --git 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java
 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java
index 8e787a2..b1d4b38 100644
--- 
a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java
+++ 
b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java
@@ -46,6 +46,7 @@ import com.google.common.base.Joiner;
 public class GitNotebookRepoTest {
 
   private static final String TEST_NOTE_ID = "2A94M5J1Z";
+  private static final String TEST_NOTE_ID2 = "2A94M5J2Z";
 
   private File zeppelinDir;
   private String notebooksDir;
@@ -54,7 +55,7 @@ public class GitNotebookRepoTest {
 
   @Before
   public void setUp() throws Exception {
-    String zpath = 
System.getProperty("java.io.tmpdir")+"/ZeppelinTest_"+System.currentTimeMillis();
+    String zpath = System.getProperty("java.io.tmpdir") + "/ZeppelinTest_" + 
System.currentTimeMillis();
     zeppelinDir = new File(zpath);
     zeppelinDir.mkdirs();
     new File(zeppelinDir, "conf").mkdirs();
@@ -64,8 +65,11 @@ public class GitNotebookRepoTest {
     notebookDir.mkdirs();
 
     String testNoteDir = Joiner.on(File.separator).join(notebooksDir, 
TEST_NOTE_ID);
+    String testNoteDir2 = Joiner.on(File.separator).join(notebooksDir, 
TEST_NOTE_ID2);
     FileUtils.copyDirectory(new File(Joiner.on(File.separator).join("src", 
"test", "resources", TEST_NOTE_ID)),
-        new File(testNoteDir)
+        new File(testNoteDir));
+    FileUtils.copyDirectory(new File(Joiner.on(File.separator).join("src", 
"test", "resources", TEST_NOTE_ID2)),
+        new File(testNoteDir2)
     );
 
     System.setProperty(ConfVars.ZEPPELIN_HOME.getVarName(), 
zeppelinDir.getAbsolutePath());
@@ -106,7 +110,7 @@ public class GitNotebookRepoTest {
   }
 
   @Test
-  public void showNotebookHistory() throws GitAPIException, IOException {
+  public void showNotebookHistoryEmptyTest() throws GitAPIException, 
IOException {
     //given
     notebookRepo = new GitNotebookRepo(conf);
     assertThat(notebookRepo.list(null)).isNotEmpty();
@@ -120,7 +124,50 @@ public class GitNotebookRepoTest {
   }
 
   @Test
-  public void addCheckpoint() throws IOException {
+  public void showNotebookHistoryMultipleNotesTest() throws IOException {
+    //initial checks
+    notebookRepo = new GitNotebookRepo(conf);
+    assertThat(notebookRepo.list(null)).isNotEmpty();
+    assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID)).isTrue();
+    assertThat(containsNote(notebookRepo.list(null), TEST_NOTE_ID2)).isTrue();
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, null)).isEmpty();
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, null)).isEmpty();
+
+    //add commit to both notes
+    notebookRepo.checkpoint(TEST_NOTE_ID, "first commit, note1", null);
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, 
null).size()).isEqualTo(1);
+    notebookRepo.checkpoint(TEST_NOTE_ID2, "first commit, note2", null);
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, 
null).size()).isEqualTo(1);
+
+    //modify, save and checkpoint first note
+    Note note = notebookRepo.get(TEST_NOTE_ID, null);
+    Paragraph p = note.addParagraph();
+    Map<String, Object> config = p.getConfig();
+    config.put("enabled", true);
+    p.setConfig(config);
+    p.setText("%md note1 test text");
+    notebookRepo.save(note, null);
+    assertThat(notebookRepo.checkpoint(TEST_NOTE_ID, "second commit, note1", 
null)).isNotNull();
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, 
null).size()).isEqualTo(2);
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, 
null).size()).isEqualTo(1);
+    assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, "first commit, note2", 
null)).isNull();
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, 
null).size()).isEqualTo(1);
+
+    //modify, save and checkpoint second note
+    note = notebookRepo.get(TEST_NOTE_ID2, null);
+    p = note.addParagraph();
+    config = p.getConfig();
+    config.put("enabled", false);
+    p.setConfig(config);
+    p.setText("%md note2 test text");
+    notebookRepo.save(note, null);
+    assertThat(notebookRepo.checkpoint(TEST_NOTE_ID2, "second commit, note2", 
null)).isNotNull();
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID, 
null).size()).isEqualTo(2);
+    assertThat(notebookRepo.revisionHistory(TEST_NOTE_ID2, 
null).size()).isEqualTo(2);
+  }
+
+  @Test
+  public void addCheckpointTest() throws IOException {
     // initial checks
     notebookRepo = new GitNotebookRepo(conf);
     assertThat(notebookRepo.list(null)).isNotEmpty();

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/5cdc02d3/zeppelin-zengine/src/test/resources/2A94M5J2Z/note.json
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/resources/2A94M5J2Z/note.json 
b/zeppelin-zengine/src/test/resources/2A94M5J2Z/note.json
new file mode 100644
index 0000000..79fe35c
--- /dev/null
+++ b/zeppelin-zengine/src/test/resources/2A94M5J2Z/note.json
@@ -0,0 +1,87 @@
+{
+  "paragraphs": [
+    {
+      "text": "%md\n## Congratulations, it\u0027s done.\n##### You can create 
your own notebook in \u0027Notebook\u0027 menu. Good luck!",
+      "config": {
+        "colWidth": 12.0,
+        "graph": {
+          "mode": "table",
+          "height": 300.0,
+          "optionOpen": false,
+          "keys": [],
+          "values": [],
+          "groups": [],
+          "scatter": {}
+        },
+        "editorHide": true
+      },
+      "settings": {
+        "params": {},
+        "forms": {}
+      },
+      "jobName": "paragraph_1423836268492_216498320",
+      "id": "20150213-230428_1231780373",
+      "result": {
+        "code": "SUCCESS",
+        "type": "HTML",
+        "msg": "\u003ch2\u003eCongratulations, it\u0027s 
done.\u003c/h2\u003e\n\u003ch5\u003eYou can create your own notebook in 
\u0027Notebook\u0027 menu. Good luck!\u003c/h5\u003e\n"
+      },
+      "dateCreated": "Feb 13, 2015 11:04:28 PM",
+      "dateStarted": "Apr 1, 2015 9:12:18 PM",
+      "dateFinished": "Apr 1, 2015 9:12:18 PM",
+      "status": "FINISHED",
+      "progressUpdateIntervalMs": 500
+    },
+    {
+      "text": "%md\n\nAbout bank data\n\n```\nCitation Request:\n  This 
dataset is public available for research. The details are described in [Moro et 
al., 2011]. \n  Please include this citation if you plan to use this 
database:\n\n  [Moro et al., 2011] S. Moro, R. Laureano and P. Cortez. Using 
Data Mining for Bank Direct Marketing: An Application of the CRISP-DM 
Methodology. \n  In P. Novais et al. (Eds.), Proceedings of the European 
Simulation and Modelling Conference - ESM\u00272011, pp. 117-121, Guimarães, 
Portugal, October, 2011. EUROSIS.\n\n  Available at: [pdf] 
http://hdl.handle.net/1822/14838\n                [bib] 
http://www3.dsi.uminho.pt/pcortez/bib/2011-esm-1.txt\n```";,
+      "config": {
+        "colWidth": 12.0,
+        "graph": {
+          "mode": "table",
+          "height": 300.0,
+          "optionOpen": false,
+          "keys": [],
+          "values": [],
+          "groups": [],
+          "scatter": {}
+        },
+        "editorHide": true
+      },
+      "settings": {
+        "params": {},
+        "forms": {}
+      },
+      "jobName": "paragraph_1427420818407_872443482",
+      "id": "20150326-214658_12335843",
+      "result": {
+        "code": "SUCCESS",
+        "type": "HTML",
+        "msg": "\u003cp\u003eAbout bank 
data\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eCitation Request:\n  This 
dataset is public available for research. The details are described in [Moro et 
al., 2011]. \n  Please include this citation if you plan to use this 
database:\n\n  [Moro et al., 2011] S. Moro, R. Laureano and P. Cortez. Using 
Data Mining for Bank Direct Marketing: An Application of the CRISP-DM 
Methodology. \n  In P. Novais et al. (Eds.), Proceedings of the European 
Simulation and Modelling Conference - ESM\u00272011, pp. 117-121, Guimarães, 
Portugal, October, 2011. EUROSIS.\n\n  Available at: [pdf] 
http://hdl.handle.net/1822/14838\n                [bib] 
http://www3.dsi.uminho.pt/pcortez/bib/2011-esm-1.txt\n\u003c/code\u003e\u003c/pre\u003e\n";
+      },
+      "dateCreated": "Mar 26, 2015 9:46:58 PM",
+      "dateStarted": "Jul 3, 2015 1:44:56 PM",
+      "dateFinished": "Jul 3, 2015 1:44:56 PM",
+      "status": "FINISHED",
+      "progressUpdateIntervalMs": 500
+    },
+    {
+      "config": {},
+      "settings": {
+        "params": {},
+        "forms": {}
+      },
+      "jobName": "paragraph_1435955447812_-158639899",
+      "id": "20150703-133047_853701097",
+      "dateCreated": "Jul 3, 2015 1:30:47 PM",
+      "status": "READY",
+      "progressUpdateIntervalMs": 500
+    }
+  ],
+  "name": "Sample note - excerpt from Zeppelin Tutorial",
+  "id": "2A94M5J2Z",
+  "angularObjects": {},
+  "config": {
+    "looknfeel": "default"
+  },
+  "info": {}
+}
\ No newline at end of file

Reply via email to