You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2015/11/24 18:51:46 UTC

incubator-zeppelin git commit: ZEPPELIN-371 : Import a notebook

Repository: incubator-zeppelin
Updated Branches:
  refs/heads/master f162615fb -> fa5057cfd


ZEPPELIN-371 : Import a notebook

Import a notebook by either an external URL or uploading a valid JSON.

<img width="429" alt="screen shot 2015-10-28 at 4 53 58 pm" src="https://cloud.githubusercontent.com/assets/674497/10787159/c15c0dd6-7d94-11e5-9617-29d2361d046b.png">

<img width="1335" alt="screen shot 2015-10-28 at 4 56 30 pm" src="https://cloud.githubusercontent.com/assets/674497/10787208/046af056-7d95-11e5-99a5-3387fee393ef.png">

<img width="1171" alt="screen shot 2015-10-28 at 4 56 55 pm" src="https://cloud.githubusercontent.com/assets/674497/10787209/046e05fc-7d95-11e5-813d-ec3856a5c207.png">

<img width="1440" alt="screen shot 2015-10-28 at 4 55 29 pm" src="https://cloud.githubusercontent.com/assets/674497/10787158/c15be87e-7d94-11e5-9cde-39c0008a53bb.png">

Author: Prabhjyot Singh <pr...@gmail.com>

Closes #374 from prabhjyotsingh/ZEPPELIN-371 and squashes the following commits:

35e1e02 [Prabhjyot Singh] review changes; uniform naming: renaming IMPORT_NOTEBOOK to IMPORT_NOTE
246ae8b [Prabhjyot Singh] Fixing test case
3b8816f [Prabhjyot Singh] Import a notebook as JSON file or external URL


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

Branch: refs/heads/master
Commit: fa5057cfd084ed36093fe032faad7f59ff22c28e
Parents: f162615
Author: Prabhjyot Singh <pr...@gmail.com>
Authored: Tue Nov 24 11:28:33 2015 +0530
Committer: Lee moon soo <mo...@apache.org>
Committed: Wed Nov 25 02:52:25 2015 +0900

----------------------------------------------------------------------
 .../org/apache/zeppelin/socket/Message.java     |   2 +
 .../apache/zeppelin/socket/NotebookServer.java  |  69 +++-
 .../java/org/apache/zeppelin/ZeppelinIT.java    |   2 +-
 .../zeppelin/socket/NotebookServerTest.java     |  21 +
 zeppelin-web/src/app/home/home.css              | 382 ++++++++++++++++++-
 zeppelin-web/src/app/home/home.html             |   2 +
 .../noteName-import/note-import-dialog.html     |  76 ++++
 .../notenameImport.controller.js                | 110 ++++++
 .../websocketEvents/websocketMsg.service.js     |   9 +
 zeppelin-web/src/index.html                     |   4 +
 10 files changed, 667 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java
index c51cfe3..7a1c749 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java
@@ -55,6 +55,8 @@ public class Message {
     CLONE_NOTE, // [c-s] clone new notebook
                 // @param id id of note to clone
                 // @param name name fpor the cloned note
+    IMPORT_NOTE,  // [c-s] import notebook
+                  // @param object notebook
     NOTE_UPDATE,
 
     RUN_PARAGRAPH, // [c-s] run paragraph

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/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 654d782..114582f 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
@@ -16,20 +16,17 @@
  */
 package org.apache.zeppelin.socket;
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.UnknownHostException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import javax.servlet.http.HttpServletRequest;
+
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
 import org.apache.zeppelin.display.AngularObject;
 import org.apache.zeppelin.display.AngularObjectRegistry;
 import org.apache.zeppelin.display.AngularObjectRegistryListener;
+import org.apache.zeppelin.display.Input;
 import org.apache.zeppelin.interpreter.InterpreterResult;
 import org.apache.zeppelin.interpreter.InterpreterSetting;
 import org.apache.zeppelin.notebook.JobListenerFactory;
@@ -119,6 +116,9 @@ public class NotebookServer extends WebSocketServlet implements
           case CLONE_NOTE:
             cloneNote(conn, notebook, messagereceived);
             break;
+          case IMPORT_NOTE:
+            importNote(conn, notebook, messagereceived);
+            break;
           case COMMIT_PARAGRAPH:
             updateParagraph(conn, notebook, messagereceived);
             break;
@@ -171,7 +171,7 @@ public class NotebookServer extends WebSocketServlet implements
     }
   }
 
-  private Message deserializeMessage(String msg) {
+  protected Message deserializeMessage(String msg) {
     return gson.fromJson(msg, Message.class);
   }
 
@@ -467,6 +467,61 @@ public class NotebookServer extends WebSocketServlet implements
     broadcastNoteList();
   }
 
+  protected Note importNote(NotebookSocket conn, Notebook notebook, Message fromMessage)
+      throws IOException {
+
+    Note note = notebook.createNote();
+    if (fromMessage != null) {
+      String noteName = (String) ((Map) fromMessage.get("notebook")).get("name");
+      if (noteName == null || noteName.isEmpty()) {
+        noteName = "Note " + note.getId();
+      }
+      note.setName(noteName);
+      ArrayList<Map> paragraphs = ((Map<String, ArrayList>) fromMessage.get("notebook"))
+          .get("paragraphs");
+      if (paragraphs.size() > 0) {
+        for (Map paragraph : paragraphs) {
+          try {
+            Paragraph p = note.addParagraph();
+            String text = (String) paragraph.get("text");
+            p.setText(text);
+            p.setTitle((String) paragraph.get("title"));
+            Map<String, Object> params = (Map<String, Object>) ((Map) paragraph
+                .get("settings")).get("params");
+            Map<String, Input> forms = (Map<String, Input>) ((Map) paragraph
+                .get("settings")).get("forms");
+            if (params != null) {
+              p.settings.setParams(params);
+            }
+            if (forms != null) {
+              p.settings.setForms(forms);
+            }
+            Map<String, Object> result = (Map) paragraph.get("result");
+            if (result != null) {
+              InterpreterResult.Code code = InterpreterResult.Code
+                  .valueOf((String) result.get("code"));
+              InterpreterResult.Type type = InterpreterResult.Type
+                  .valueOf((String) result.get("type"));
+              String msg = (String) result.get("msg");
+              p.setReturn(new InterpreterResult(code, type, msg), null);
+            }
+
+            Map<String, Object> config = (Map<String, Object>) paragraph
+                .get("config");
+            p.setConfig(config);
+          } catch (Exception e) {
+            LOG.error("Exception while setting parameter in paragraph", e);
+          }
+        }
+      }
+    }
+
+    note.persist();
+    broadcastNote(note);
+    broadcastNoteList();
+    return note;
+  }
+
   private void removeParagraph(NotebookSocket conn, Notebook notebook,
       Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java
index dc188f8..c1b10ce 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ZeppelinIT.java
@@ -299,7 +299,7 @@ public class ZeppelinIT {
       notebookTitles.add(el.getText());
     }
     
-    WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a"));
+    WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a[contains(.,'Create new note')]"));
     createNoteLink.click();
 
     WebDriverWait block = new WebDriverWait(driver, 10);

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
index 5275d81..faef287 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
@@ -136,6 +136,27 @@ public class NotebookServerTest extends AbstractTestRestApi {
     notebook.removeNote(note1.getId());
   }
 
+  @Test
+  public void testImportNotebook() throws IOException {
+    String msg = "{\"op\":\"IMPORT_NOTE\",\"data\":" +
+        "{\"notebook\":{\"paragraphs\": [{\"text\": \"Test " +
+        "paragraphs import\",\"config\":{},\"settings\":{}}]," +
+        "\"name\": \"Test Zeppelin notebook import\",\"config\": " +
+        "{}}}}";
+    Message messageReceived = notebookServer.deserializeMessage(msg);
+    Note note = null;
+    try {
+      note = notebookServer.importNote(null, notebook, messageReceived);
+    } catch (NullPointerException e) {
+      //broadcastNoteList(); failed nothing to worry.
+    }
+
+    assertNotEquals(null, notebook.getNote(note.getId()));
+    assertEquals("Test Zeppelin notebook import", notebook.getNote(note.getId()).getName());
+    assertEquals("Test paragraphs import", notebook.getNote(note.getId()).getParagraphs().get(0).getText());
+    notebook.removeNote(note.getId());
+  }
+
   private NotebookSocket createWebSocket() {
     NotebookSocket sock = mock(NotebookSocket.class);
     when(sock.getRequest()).thenReturn(createHttpServletRequest());

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-web/src/app/home/home.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.css b/zeppelin-web/src/app/home/home.css
index 0c62279..70baee9 100644
--- a/zeppelin-web/src/app/home/home.css
+++ b/zeppelin-web/src/app/home/home.css
@@ -130,30 +130,37 @@ a.navbar-brand:hover {
   .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
     color: #D3D3D3;
   }
+
   .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
     padding: 5px 15px 5px 25px;
     line-height: 20px;
   }
+
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
     color: #D3D3D3;
   }
+
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:hover,
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:focus {
     color: #fff;
     background-color: transparent;
   }
+
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a,
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:hover,
   .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:focus {
     color: #fff;
     background-color: #080808;
   }
-  .server-status{
+
+  .server-status {
     float: right;
   }
+
   .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
     background-color: #3071A9;
   }
+
   .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
     border-color: #3071A9;
   }
@@ -210,7 +217,7 @@ a.navbar-brand:hover {
 .box-heading {
   position: relative;
   max-width: 100%;
-  font-weight:300;
+  font-weight: 300;
   white-space: nowrap;
   text-overflow: ellipsis;
   vertical-align: middle;
@@ -310,3 +317,374 @@ This part should be removed when new version of bootstrap handles this issue.
 .btn-group > .popover + .btn {
   margin-left: -1px;
 }
+
+.display-inline {
+  display: inline;
+  float: left;
+}
+
+#noteImportModal .modal-body {
+  min-height: 420px;
+  overflow: hidden;
+}
+
+#noteImportModal .modal-footer {
+  min-height: 65px;
+}
+
+#noteImportModal .display-inline a {
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 5px;
+  color: #999;
+  cursor: pointer;
+  display: block;
+  float: left;
+  font-size: 98px;
+  height: 240px;
+  margin: 0 10px 16px;
+  padding-top: 60px;
+  text-align: center;
+  text-decoration: none;
+  width: 264px;
+}
+
+#noteImportModal .display-inline a:hover {
+  background-color: #eee;
+}
+
+#noteImportModal .display-inline a p {
+  font-size: 14px;
+}
+
+/* ------------------------------------------- */
+/* Slide Top
+/* ------------------------------------------- */
+.slide-top {
+  -webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+  -webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+}
+
+.slide-top.ng-enter {
+  transform: translateY(60px);
+  -ms-transform: translateY(60px);
+  -webkit-transform: translateY(60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 0;
+}
+
+.slide-top.ng-enter-active {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  opacity: 1;
+}
+
+.slide-top.ng-leave {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-top.ng-leave-active {
+  transform: translateY(60px);
+  -ms-transform: translateY(60px);
+  -webkit-transform: translateY(60px);
+  opacity: 0;
+}
+
+.slide-top.ng-hide-add {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-top.ng-hide-add.ng-hide-add-active {
+  transform: translateY(60px);
+  -ms-transform: translateY(60px);
+  -webkit-transform: translateY(60px);
+  opacity: 0;
+}
+
+.slide-top.ng-hide-remove {
+  transform: translateY(60px);
+  -ms-transform: translateY(60px);
+  -webkit-transform: translateY(60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  display: block !important;
+  opacity: 0;
+}
+
+.slide-top.ng-hide-remove.ng-hide-remove-active {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  opacity: 1;
+}
+
+/* ------------------------------------------- */
+/* Slide Right
+/* ------------------------------------------- */
+.slide-right {
+  -webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+  -webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+}
+
+.slide-right.ng-enter {
+  transform: translateX(60px);
+  -ms-transform: translateX(60px);
+  -webkit-transform: translateX(60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 0;
+}
+
+.slide-right.ng-enter-active {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  opacity: 1;
+}
+
+.slide-right.ng-leave {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-right.ng-leave-active {
+  transform: translateX(60px);
+  -ms-transform: translateX(60px);
+  -webkit-transform: translateX(60px);
+  opacity: 0;
+}
+
+.slide-right.ng-hide-add {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-right.ng-hide-add.ng-hide-add-active {
+  transform: translateX(60px);
+  -ms-transform: translateX(60px);
+  -webkit-transform: translateX(60px);
+  opacity: 0;
+}
+
+.slide-right.ng-hide-remove {
+  transform: translateX(60px);
+  -ms-transform: translateX(60px);
+  -webkit-transform: translateX(60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  display: block !important;
+  opacity: 0;
+}
+
+.slide-right.ng-hide-remove.ng-hide-remove-active {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  opacity: 1;
+}
+
+/* ------------------------------------------- */
+/* Slide Left
+/* ------------------------------------------- */
+.slide-left {
+  -webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+  -webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+}
+
+.slide-left.ng-enter {
+  transform: translateX(-60px);
+  -ms-transform: translateX(-60px);
+  -webkit-transform: translateX(-60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 0;
+}
+
+.slide-left.ng-enter-active {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  opacity: 1;
+}
+
+.slide-left.ng-leave {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-left.ng-leave-active {
+  transform: translateX(-60px);
+  -ms-transform: translateX(-60px);
+  -webkit-transform: translateX(-60px);
+  opacity: 0;
+}
+
+.slide-left.ng-hide-add {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-left.ng-hide-add.ng-hide-add-active {
+  transform: translateX(-60px);
+  -ms-transform: translateX(-60px);
+  -webkit-transform: translateX(-60px);
+  opacity: 0;
+}
+
+.slide-left.ng-hide-remove {
+  transform: translateX(-60px);
+  -ms-transform: translateX(-60px);
+  -webkit-transform: translateX(-60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  display: block !important;
+  opacity: 0;
+}
+
+.slide-left.ng-hide-remove.ng-hide-remove-active {
+  transform: translateX(0);
+  -ms-transform: translateX(0);
+  -webkit-transform: translateX(0);
+  opacity: 1;
+}
+
+/* ------------------------------------------- */
+/* Slide Down
+/* ------------------------------------------- */
+.slide-down {
+  -webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+  -webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  -o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+  /* easeOutQuad */
+}
+
+.slide-down.ng-enter {
+  transform: translateY(-60px);
+  -ms-transform: translateY(-60px);
+  -webkit-transform: translateY(-60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 0;
+}
+
+.slide-down.ng-enter-active {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  opacity: 1;
+}
+
+.slide-down.ng-leave {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-down.ng-leave-active {
+  transform: translateY(-60px);
+  -ms-transform: translateY(-60px);
+  -webkit-transform: translateY(-60px);
+  opacity: 0;
+}
+
+.slide-down.ng-hide-add {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  opacity: 1;
+}
+
+.slide-down.ng-hide-add.ng-hide-add-active {
+  transform: translateY(-60px);
+  -ms-transform: translateY(-60px);
+  -webkit-transform: translateY(-60px);
+  opacity: 0;
+}
+
+.slide-down.ng-hide-remove {
+  transform: translateY(-60px);
+  -ms-transform: translateY(-60px);
+  -webkit-transform: translateY(-60px);
+  transition-duration: 250ms;
+  -webkit-transition-duration: 250ms;
+  display: block !important;
+  opacity: 0;
+}
+
+.slide-down.ng-hide-remove.ng-hide-remove-active {
+  transform: translateY(0);
+  -ms-transform: translateY(0);
+  -webkit-transform: translateY(0);
+  opacity: 1;
+}

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-web/src/app/home/home.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.html b/zeppelin-web/src/app/home/home.html
index cdefa69..56e6dc4 100644
--- a/zeppelin-web/src/app/home/home.html
+++ b/zeppelin-web/src/app/home/home.html
@@ -29,6 +29,8 @@ limitations under the License.
           <h4>Notebook</h4>
 
           <div>
+            <h5><a href="" data-toggle="modal" data-target="#noteImportModal" style="text-decoration: none;">
+              <i style="font-size: 15px;" class="fa fa-upload"></i> Import note</a></h5>
             <h5><a href="" data-toggle="modal" data-target="#noteNameModal" style="text-decoration: none;">
               <i style="font-size: 15px;" class="icon-notebook"></i> Create new note</a></h5>
             <ul style="list-style-type: none;">

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-web/src/components/noteName-import/note-import-dialog.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/noteName-import/note-import-dialog.html b/zeppelin-web/src/components/noteName-import/note-import-dialog.html
new file mode 100644
index 0000000..524e4d2
--- /dev/null
+++ b/zeppelin-web/src/components/noteName-import/note-import-dialog.html
@@ -0,0 +1,76 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+  <div id="noteImportModal" class="modal fade" role="dialog"
+       tabindex='-1'>
+    <div class="modal-dialog">
+
+      <!-- Modal content-->
+      <div class="modal-content" id="NoteImportCtrl" ng-init="NoteImportInit">
+        <div class="modal-header">
+          <button type="button" class="close" data-dismiss="modal">&times;</button>
+          <h4 class="modal-title">Import new note</h4>
+        </div>
+        <div class="modal-body">
+
+          <div class="form-group">
+            <label for="noteImportName">Import AS</label>
+            <input placeholder="Note name" type="text" class="form-control" id="noteImportName"
+                   ng-model="note.noteImportName">
+          </div>
+
+          <div class="form-group" ng-show="note.errorText">
+            <div class="alert alert-danger">{{note.errorText}}</div>
+          </div>
+
+          <div class="form-group slide-left" ng-show="note.step1">
+            <div class="display-inline">
+              <a class="fa fa-cloud-upload import-file-upload" ng-click="uploadFile()">
+                <p>Choose a JSON here</p>
+              </a>
+            </div>
+            <div style="display: none">
+              <input placeholder="Note name" type="file" class="form-control" id="noteImportFile"
+                     ng-model="note.importFile" onchange="angular.element(this).scope().importFile(this)">
+            </div>
+            <div class="display-inline">
+              <a href="javascript:void(0);" ng-click="uploadURL()" class="fa fa-link">
+                <p>Add from URL</p>
+              </a>
+            </div>
+          </div>
+
+          <div class="form-group slide-right" ng-show="note.step2">
+
+            <label for="noteImportUrl">URL</label>
+            <input placeholder="Note name" type="text" class="form-control" id="noteImportUrl"
+                   ng-model="note.importUrl">
+          </div>
+
+        </div>
+        <div class="modal-footer">
+          <div ng-show="note.step2">
+            <button type="button" id="importBackButton"
+                    class="btn btn-default"
+                    ng-click="noteimportctrl.importBack()">Back
+            </button>
+            <button type="button" id="importNoteButton"
+                    class="btn btn-default"
+                    ng-click="noteimportctrl.importNote()">Import Note
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/noteName-import/notenameImport.controller.js b/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
new file mode 100644
index 0000000..d48179d
--- /dev/null
+++ b/zeppelin-web/src/components/noteName-import/notenameImport.controller.js
@@ -0,0 +1,110 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+angular.module('zeppelinWebApp').controller('NoteImportCtrl', function($scope, $timeout, websocketMsgSrv) {
+  var vm = this;
+  $scope.note = {};
+  $scope.note.step1 = true;
+  $scope.note.step2 = false;
+
+  vm.resetFlags = function() {
+    $scope.note = {};
+    $scope.note.step1 = true;
+    $scope.note.step2 = false;
+    angular.element('#noteImportFile').val('');
+  };
+
+  $scope.uploadFile = function() {
+    angular.element('#noteImportFile').click();
+  };
+
+  $scope.importFile = function(element) {
+    $scope.note.errorText = '';
+    $scope.note.importFile = element.files[0];
+    var file = $scope.note.importFile;
+    var reader = new FileReader();
+
+    reader.onloadend = function() {
+      vm.processImportJson(reader.result);
+    };
+
+    if (file) {
+      reader.readAsText(file);
+    }
+  };
+
+  $scope.uploadURL = function() {
+    $scope.note.errorText = '';
+    $scope.note.step1 = false;
+    $timeout(function() {
+      $scope.note.step2 = true;
+    }, 400);
+  };
+
+  vm.importBack = function() {
+    $scope.note.errorText = '';
+    $timeout(function() {
+      $scope.note.step1 = true;
+    }, 400);
+    $scope.note.step2 = false;
+  };
+
+  vm.importNote = function() {
+    $scope.note.errorText = '';
+    if ($scope.note.importUrl) {
+      jQuery.getJSON($scope.note.importUrl, function(result) {
+        vm.processImportJson(result);
+      }).fail(function() {
+        $scope.note.errorText = 'Unable to Fetch URL';
+        $scope.$apply();
+      });
+    }
+    else {
+      $scope.note.errorText = 'Enter URL';
+      $scope.$apply();
+    }
+  };
+
+  vm.processImportJson = function(result) {
+    if (typeof result !== 'object') {
+      try {
+        result = JSON.parse(result);
+      } catch (e) {
+        $scope.note.errorText = 'JSON parse exception';
+        $scope.$apply();
+        return;
+      }
+
+    }
+    if (result.paragraphs && result.paragraphs.length > 0) {
+      if (!$scope.note.noteImportName) {
+        $scope.note.noteImportName = result.name;
+      } else {
+        result.name = $scope.note.noteImportName;
+      }
+      websocketMsgSrv.importNotebook(result);
+      //angular.element('#noteImportModal').modal('hide');
+    } else {
+      $scope.note.errorText = 'Invalid JSON';
+    }
+    $scope.$apply();
+  };
+
+  $scope.$on('setNoteMenu', function(event, notes) {
+    vm.resetFlags();
+    angular.element('#noteImportModal').modal('hide');
+  });
+});

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/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 6022543..a10bc87 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
@@ -113,6 +113,15 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
       });
     },
 
+    importNotebook: function(notebook) {
+      websocketEvents.sendNewEvent({
+        op: 'IMPORT_NOTE',
+        data: {
+          notebook: notebook
+        }
+      });
+    },
+
     isConnected: function(){
       return websocketEvents.isConnected();
     }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/fa5057cf/zeppelin-web/src/index.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/index.html b/zeppelin-web/src/index.html
index b8dd489..0d065a5 100644
--- a/zeppelin-web/src/index.html
+++ b/zeppelin-web/src/index.html
@@ -73,6 +73,9 @@ limitations under the License.
     <div ng-controller="NotenameCtrl as notenamectrl">
    		 <div id="note-modal-container" ng-include src="'components/noteName-create/note-name-dialog.html'"></div>
     </div>
+    <div ng-controller="NoteImportCtrl as noteimportctrl">
+      <div id="note-import-container" ng-include src="'components/noteName-import/note-import-dialog.html'"></div>
+    </div>
     <!-- build:js(.) scripts/oldieshim.js -->
     <!--[if lt IE 9]>
 <script src="bower_components/es5-shim/es5-shim.js"></script>
@@ -129,6 +132,7 @@ limitations under the License.
     <script src="components/navbar/navbar.controller.js"></script>
     <script src="components/ngescape/ngescape.directive.js"></script>
     <script src="components/noteName-create/notename.controller.js"></script>
+    <script src="components/noteName-import/notenameImport.controller.js"></script>
     <script src="components/popover-html-unsafe/popover-html-unsafe.directive.js"></script>
     <script src="components/ngenter/ngenter.directive.js"></script>
     <script src="components/dropdowninput/dropdowninput.directive.js"></script>