You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mi...@apache.org on 2016/11/05 04:41:23 UTC
zeppelin git commit: [ZEPPELIN-1564] Enable note deletion and
paragraph output clear from main page
Repository: zeppelin
Updated Branches:
refs/heads/master 0e087455a -> dd20e7bf8
[ZEPPELIN-1564] Enable note deletion and paragraph output clear from main page
### What is this PR for?
- Enables removing note and clear all paragraph's output from Zeppelin main page.
- Add rest api for clearing all paragraph output
Next possible improvement can be removing notes in folder level and rename folder.
### What type of PR is it?
Improvement
### Todos
* [x] - Merge #1567 and apply security to `clearAllParagraphOutput` rest api method
### What is the Jira issue?
[ZEPPELIN-1564](https://issues.apache.org/jira/browse/ZEPPELIN-1564)
### Screenshots (if appropriate)

### Questions:
- Does the licenses files need update? no
- Is there breaking changes for older versions? no
- Does this needs documentation? yes
Author: Mina Lee <mi...@apache.org>
Closes #1565 from minahlee/ZEPPELIN-1564 and squashes the following commits:
749aebe [Mina Lee] Merge branch 'master' of https://github.com/apache/zeppelin into ZEPPELIN-1564
1393ee9 [Mina Lee] Rename class name from UnauthorizedException to ForbiddenException Update clear output rest api doc response code
2ee452e [Mina Lee] Add auth check before clearing all paragraph
fb7e6ae [Mina Lee] Merge branch 'master' of https://github.com/apache/zeppelin into ZEPPELIN-1564
f349dbf [Mina Lee] Change post to put
7eb3521 [Mina Lee] Give writer permission to clear output
dea3ef6 [Mina Lee] Remove unused import
d66600c [Mina Lee] Add rest api endpoint for clear paragraph result to document
3d19141 [Mina Lee] Add rest api for clear all paragraph result and add test
98d7604 [Mina Lee] Add clearAllParagraphOutput unit test
4adddb4 [Mina Lee] Clear all paragraphs and remove note from main page
Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/dd20e7bf
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/dd20e7bf
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/dd20e7bf
Branch: refs/heads/master
Commit: dd20e7bf8bf7b307f72b4f601fa675e06f7d03c5
Parents: 0e08745
Author: Mina Lee <mi...@apache.org>
Authored: Sat Nov 5 12:49:36 2016 +0900
Committer: Mina Lee <mi...@apache.org>
Committed: Sat Nov 5 13:41:11 2016 +0900
----------------------------------------------------------------------
docs/rest-api/rest-notebook.md | 38 ++++++++++++++-
.../apache/zeppelin/rest/NotebookRestApi.java | 29 +++++++++--
.../rest/exception/ForbiddenException.java | 51 ++++++++++++++++++++
.../rest/exception/UnauthorizedException.java | 50 -------------------
.../apache/zeppelin/socket/NotebookServer.java | 22 +++++++++
.../zeppelin/rest/AbstractTestRestApi.java | 2 +-
.../zeppelin/rest/NotebookRestApiTest.java | 45 +++++++++++++++--
.../rest/NotebookSecurityRestApiTest.java | 8 +--
zeppelin-web/src/app/home/home.controller.js | 15 ++++--
zeppelin-web/src/app/home/home.html | 16 +++++-
.../src/app/notebook/notebook-actionBar.html | 2 +-
.../src/app/notebook/notebook.controller.js | 35 +++-----------
.../components/noteAction/noteAction.service.js | 51 ++++++++++++++++++++
.../websocketEvents/websocketMsg.service.js | 4 ++
zeppelin-web/src/index.html | 1 +
.../java/org/apache/zeppelin/notebook/Note.java | 11 +++++
.../zeppelin/notebook/socket/Message.java | 5 +-
.../org/apache/zeppelin/notebook/NoteTest.java | 20 ++++++++
18 files changed, 305 insertions(+), 100 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/docs/rest-api/rest-notebook.md
----------------------------------------------------------------------
diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md
index 1e49d1e..46f2cd1 100644
--- a/docs/rest-api/rest-notebook.md
+++ b/docs/rest-api/rest-notebook.md
@@ -493,7 +493,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
<col width="200">
<tr>
<td>Description</td>
- <td> This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution
+ <td>This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution
</td>
</tr>
<tr>
@@ -972,3 +972,39 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple
</tr>
</tr>
</table>
+
+<br />
+### Clear all paragraph result
+ <table class="table-configuration">
+ <col width="200">
+ <tr>
+ <td>Description</td>
+ <td>This ```PUT``` method clear all paragraph results from note of given id.
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/clear```</td>
+ </tr>
+ <tr>
+ <td>Success code</td>
+ <td>200</td>
+ </tr>
+ <tr>
+ <td>Forbidden code</td>
+ <td>401</td>
+ </tr>
+ <tr>
+ <td>Not Found code</td>
+ <td>404</td>
+ </tr>
+ <tr>
+ <td>Fail code</td>
+ <td>500</td>
+ </tr>
+ <tr>
+ <td>sample JSON response</td>
+ <td><pre>{"status": "OK"}</pre></td>
+ </tr>
+ </tr>
+ </table>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
index 5b27d0e..52f7d11 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java
@@ -43,7 +43,7 @@ import org.apache.zeppelin.notebook.Notebook;
import org.apache.zeppelin.notebook.NotebookAuthorization;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.rest.exception.NotFoundException;
-import org.apache.zeppelin.rest.exception.UnauthorizedException;
+import org.apache.zeppelin.rest.exception.ForbiddenException;
import org.apache.zeppelin.rest.message.CronRequest;
import org.apache.zeppelin.rest.message.NewNoteRequest;
import org.apache.zeppelin.rest.message.NewParagraphRequest;
@@ -124,7 +124,7 @@ public class NotebookRestApi {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.isOwner(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -136,7 +136,7 @@ public class NotebookRestApi {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.hasWriteAuthorization(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -148,7 +148,7 @@ public class NotebookRestApi {
userAndRoles.add(SecurityUtils.getPrincipal());
userAndRoles.addAll(SecurityUtils.getRoles());
if (!notebookAuthorization.hasReadAuthorization(userAndRoles, noteId)) {
- throw new UnauthorizedException(errorMsg);
+ throw new ForbiddenException(errorMsg);
}
}
@@ -517,6 +517,27 @@ public class NotebookRestApi {
}
/**
+ * Clear result of all paragraphs REST API
+ *
+ * @param noteId ID of Note
+ * @return JSON with status.ok
+ */
+ @PUT
+ @Path("{noteId}/clear")
+ @ZeppelinApi
+ public Response clearAllParagraphOutput(@PathParam("noteId") String noteId)
+ throws IOException {
+ LOG.info("clear all paragraph output of note {}", noteId);
+ checkIfUserCanWrite(noteId, "Insufficient privileges you cannot clear this note");
+
+ Note note = notebook.getNote(noteId);
+ checkIfNoteIsNotNull(note);
+ note.clearAllParagraphOutput();
+
+ return new JsonResponse(Status.OK, "").build();
+ }
+
+ /**
* Run note jobs REST API
*
* @param noteId ID of Note
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
new file mode 100644
index 0000000..04deb42
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/ForbiddenException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.zeppelin.rest.exception;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.zeppelin.utils.ExceptionUtils;
+
+/**
+ * UnauthorizedException handler for WebApplicationException.
+ *
+ */
+public class ForbiddenException extends WebApplicationException {
+ private static final long serialVersionUID = 4394749068760407567L;
+ private static final String FORBIDDEN_MSG = "Not allowed to access";
+
+ public ForbiddenException() {
+ super(forbiddenJson(FORBIDDEN_MSG));
+ }
+
+ private static Response forbiddenJson(String message) {
+ return ExceptionUtils.jsonResponseContent(FORBIDDEN, message);
+ }
+
+ public ForbiddenException(Throwable cause, String message) {
+ super(cause, forbiddenJson(message));
+ }
+
+ public ForbiddenException(String message) {
+ super(forbiddenJson(message));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java
deleted file mode 100644
index 7b968ab..0000000
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/exception/UnauthorizedException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-package org.apache.zeppelin.rest.exception;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-
-import org.apache.zeppelin.utils.ExceptionUtils;
-
-/**
- * UnauthorizedException handler for WebApplicationException.
- *
- */
-public class UnauthorizedException extends WebApplicationException {
- private static final long serialVersionUID = 4394749068760407567L;
- private static final String UNAUTHORIZED_MSG = "Authorization required";
-
- public UnauthorizedException() {
- super(unauthorizedJson(UNAUTHORIZED_MSG));
- }
-
- private static Response unauthorizedJson(String message) {
- return ExceptionUtils.jsonResponseContent(FORBIDDEN, message);
- }
-
- public UnauthorizedException(Throwable cause, String message) {
- super(cause, unauthorizedJson(message));
- }
-
- public UnauthorizedException(String message) {
- super(unauthorizedJson(message));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 3e137b8..6cba536 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
@@ -228,6 +228,9 @@ public class NotebookServer extends WebSocketServlet implements
case PARAGRAPH_CLEAR_OUTPUT:
clearParagraphOutput(conn, userAndRoles, notebook, messagereceived);
break;
+ case PARAGRAPH_CLEAR_ALL_OUTPUT:
+ clearAllParagraphOutput(conn, userAndRoles, notebook, messagereceived);
+ break;
case NOTE_UPDATE:
updateNote(conn, userAndRoles, notebook, messagereceived);
break;
@@ -822,6 +825,25 @@ public class NotebookServer extends WebSocketServlet implements
broadcastNoteList(subject, userAndRoles);
}
+ private void clearAllParagraphOutput(NotebookSocket conn, HashSet<String> userAndRoles,
+ Notebook notebook, Message fromMessage)
+ throws IOException {
+ final String noteId = (String) fromMessage.get("id");
+ if (StringUtils.isBlank(noteId)) {
+ return;
+ }
+ Note note = notebook.getNote(noteId);
+ NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
+ if (!notebookAuthorization.isWriter(noteId, userAndRoles)) {
+ permissionError(conn, "clear output", fromMessage.principal,
+ userAndRoles, notebookAuthorization.getOwners(noteId));
+ return;
+ }
+
+ note.clearAllParagraphOutput();
+ broadcastNote(note);
+ }
+
protected Note importNote(NotebookSocket conn, HashSet<String> userAndRoles,
Notebook notebook, Message fromMessage)
throws IOException {
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
index 6d10337..2ff8d40 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java
@@ -539,7 +539,7 @@ public abstract class AbstractTestRestApi {
/** Status code matcher */
- protected Matcher<? super HttpMethodBase> isForbiden() { return responsesWith(403); }
+ protected Matcher<? super HttpMethodBase> isForbidden() { return responsesWith(403); }
protected Matcher<? super HttpMethodBase> isAllowed() {
return responsesWith(200);
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
index 36b0f1c..15b6903 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java
@@ -18,15 +18,14 @@
package org.apache.zeppelin.rest;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.notebook.Note;
-import org.apache.zeppelin.notebook.NotebookAuthorization;
-import org.apache.zeppelin.notebook.NotebookAuthorizationInfoSaving;
+import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.server.ZeppelinServer;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.AfterClass;
@@ -37,12 +36,11 @@ import org.junit.Test;
import org.junit.runners.MethodSorters;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
/**
@@ -179,6 +177,43 @@ public class NotebookRestApiTest extends AbstractTestRestApi {
ZeppelinServer.notebook.removeNote(clonedNoteId, anonymous);
}
+
+ @Test
+ public void testClearAllParagraphOutput() throws IOException {
+ // Create note and set result explicitly
+ Note note = ZeppelinServer.notebook.createNote(anonymous);
+ Paragraph p1 = note.addParagraph();
+ InterpreterResult result = new InterpreterResult(InterpreterResult.Code.SUCCESS, InterpreterResult.Type.TEXT, "result");
+ p1.setResult(result);
+
+ Paragraph p2 = note.addParagraph();
+ p2.setReturn(result, new Throwable());
+
+ // clear paragraph result
+ PutMethod put = httpPut("/notebook/" + note.getId() + "/clear", "");
+ LOG.info("test clear paragraph output response\n" + put.getResponseBodyAsString());
+ assertThat(put, isAllowed());
+ put.releaseConnection();
+
+ // check if paragraph results are cleared
+ GetMethod get = httpGet("/notebook/" + note.getId() + "/paragraph/" + p1.getId());
+ assertThat(get, isAllowed());
+ Map<String, Object> resp1 = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
+ }.getType());
+ Map<String, Object> resp1Body = (Map<String, Object>) resp1.get("body");
+ assertNull(resp1Body.get("result"));
+
+ get = httpGet("/notebook/" + note.getId() + "/paragraph/" + p2.getId());
+ assertThat(get, isAllowed());
+ Map<String, Object> resp2 = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
+ }.getType());
+ Map<String, Object> resp2Body = (Map<String, Object>) resp2.get("body");
+ assertNull(resp2Body.get("result"));
+ get.releaseConnection();
+
+ //cleanup
+ ZeppelinServer.notebook.removeNote(note.getId(), anonymous);
+ }
}
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
index 3c5978f..0c714fd 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookSecurityRestApiTest.java
@@ -82,10 +82,10 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
//set permission
String payload = "{ \"owners\": [\"admin\"], \"readers\": [\"user2\"], \"writers\": [\"user2\"] }";
PutMethod put = httpPut("/notebook/" + noteId + "/permissions", payload , "admin", "password1");
- assertThat("test set note premission method:", put, isAllowed());
+ assertThat("test set note permission method:", put, isAllowed());
put.releaseConnection();
- userTryGetNote(noteId, "user1", "password2", isForbiden());
+ userTryGetNote(noteId, "user1", "password2", isForbidden());
userTryGetNote(noteId, "user2", "password3", isAllowed());
@@ -99,10 +99,10 @@ public class NotebookSecurityRestApiTest extends AbstractTestRestApi {
//set permission
String payload = "{ \"owners\": [\"admin\", \"user1\"], \"readers\": [\"user2\"], \"writers\": [\"user2\"] }";
PutMethod put = httpPut("/notebook/" + noteId + "/permissions", payload , "admin", "password1");
- assertThat("test set note premission method:", put, isAllowed());
+ assertThat("test set note permission method:", put, isAllowed());
put.releaseConnection();
- userTryRemoveNote(noteId, "user2", "password3", isForbiden());
+ userTryRemoveNote(noteId, "user2", "password3", isForbidden());
userTryRemoveNote(noteId, "user1", "password2", isAllowed());
Note deletedNote = ZeppelinServer.notebook.getNote(noteId);
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-web/src/app/home/home.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.controller.js b/zeppelin-web/src/app/home/home.controller.js
index 171a275..1d11c79 100644
--- a/zeppelin-web/src/app/home/home.controller.js
+++ b/zeppelin-web/src/app/home/home.controller.js
@@ -22,10 +22,12 @@
'websocketMsgSrv',
'$rootScope',
'arrayOrderingSrv',
- 'ngToast'
+ 'ngToast',
+ 'noteActionSrv'
];
- function HomeCtrl($scope, noteListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv, ngToast) {
+ function HomeCtrl($scope, noteListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv,
+ ngToast, noteActionSrv) {
ngToast.dismiss();
var vm = this;
vm.notes = noteListDataFactory;
@@ -85,6 +87,13 @@
vm.notebookHome = false;
}
});
- }
+ $scope.removeNote = function(noteId) {
+ noteActionSrv.removeNote(noteId, false);
+ };
+
+ $scope.clearAllParagraphOutput = function(noteId) {
+ noteActionSrv.clearAllParagraphOutput(noteId);
+ };
+ }
})();
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 0f8e968..a8d5e56 100644
--- a/zeppelin-web/src/app/home/home.html
+++ b/zeppelin-web/src/app/home/home.html
@@ -13,10 +13,24 @@ limitations under the License.
-->
<script type="text/ng-template" id="notebook_folder_renderer.html">
- <div ng-if="node.children == null">
+ <div ng-if="node.children == null"
+ ng-mouseenter="showButton=true"
+ ng-mouseleave="showButton=false">
<a style="text-decoration: none;" href="#/notebook/{{node.id}}">
<i style="font-size: 10px;" class="icon-doc"/> {{noteName(node)}}
</a>
+ <a style="text-decoration: none;">
+ <i style="font-size: 13px; margin-left: 10px; cursor: pointer; text-decoration: none;"
+ class="fa fa-eraser" ng-show="showButton" ng-click="clearAllParagraphOutput(node.id)"
+ tooltip-placement="bottom" tooltip="Clear output">
+ </i>
+ </a>
+ <a style="text-decoration: none;">
+ <i style="font-size: 13px; margin-left: 2px; cursor: pointer; text-decoration: none;"
+ class="fa fa-trash-o" ng-show="showButton" ng-click="removeNote(node.id)"
+ tooltip-placement="bottom" tooltip="Remove note">
+ </i>
+ </a>
</div>
<div ng-if="node.children != null">
<a style="text-decoration: none; cursor: pointer;" ng-click="toggleFolderNode(node)">
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 38406df..16f0e10 100644
--- a/zeppelin-web/src/app/notebook/notebook-actionBar.html
+++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html
@@ -43,7 +43,7 @@ limitations under the License.
</button>
<button type="button"
class="btn btn-default btn-xs"
- ng-click="clearAllParagraphOutput()"
+ ng-click="clearAllParagraphOutput(note.id)"
ng-hide="viewOnly"
ng-class="{'disabled':isNoteRunning()}"
tooltip-placement="bottom" tooltip="Clear output">
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 dbb7b94..f308047 100644
--- a/zeppelin-web/src/app/notebook/notebook.controller.js
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -27,12 +27,13 @@
'baseUrlSrv',
'$timeout',
'saveAsService',
- 'ngToast'
+ 'ngToast',
+ 'noteActionSrv'
];
function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope,
$http, websocketMsgSrv, baseUrlSrv, $timeout, saveAsService,
- ngToast) {
+ ngToast, noteActionSrv) {
ngToast.dismiss();
@@ -143,20 +144,9 @@
$scope.$broadcast('doubleClickParagraph', paragraphId);
};
- /** Remove the note and go back tot he main page */
- /** TODO(anthony): In the nearly future, go back to the main page and telle to the dude that the note have been remove */
+ // Remove the note and go back to the main page
$scope.removeNote = function(noteId) {
- BootstrapDialog.confirm({
- closable: true,
- title: '',
- message: 'Do you want to delete this note?',
- callback: function(result) {
- if (result) {
- websocketMsgSrv.deleteNote(noteId);
- $location.path('/');
- }
- }
- });
+ noteActionSrv.removeNote(noteId, true);
};
//Export notebook
@@ -230,19 +220,8 @@
}
};
- $scope.clearAllParagraphOutput = function() {
- BootstrapDialog.confirm({
- closable: true,
- title: '',
- message: 'Do you want to clear all output?',
- callback: function(result) {
- if (result) {
- _.forEach($scope.note.paragraphs, function(n, key) {
- angular.element('#' + n.id + '_paragraphColumn_main').scope().clearParagraphOutput();
- });
- }
- }
- });
+ $scope.clearAllParagraphOutput = function(noteId) {
+ noteActionSrv.clearAllParagraphOutput(noteId);
};
$scope.toggleAllEditor = function() {
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-web/src/components/noteAction/noteAction.service.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/components/noteAction/noteAction.service.js b/zeppelin-web/src/components/noteAction/noteAction.service.js
new file mode 100644
index 0000000..33e5722
--- /dev/null
+++ b/zeppelin-web/src/components/noteAction/noteAction.service.js
@@ -0,0 +1,51 @@
+/*
+ * 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';
+(function() {
+
+ angular.module('zeppelinWebApp').service('noteActionSrv', noteActionSrv);
+
+ noteActionSrv.$inject = ['websocketMsgSrv', '$location'];
+
+ function noteActionSrv(websocketMsgSrv, $location) {
+ this.removeNote = function(noteId, redirectToHome) {
+ BootstrapDialog.confirm({
+ closable: true,
+ title: '',
+ message: 'Do you want to delete this note?',
+ callback: function(result) {
+ if (result) {
+ websocketMsgSrv.deleteNote(noteId);
+ if (redirectToHome) {
+ $location.path('/');
+ }
+ }
+ }
+ });
+ };
+
+ this.clearAllParagraphOutput = function(noteId) {
+ BootstrapDialog.confirm({
+ closable: true,
+ title: '',
+ message: 'Do you want to clear all output?',
+ callback: function(result) {
+ if (result) {
+ websocketMsgSrv.clearAllParagraphOutput(noteId);
+ }
+ }
+ });
+ };
+ }
+})();
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 da75939..8c025cc 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
@@ -128,6 +128,10 @@
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_OUTPUT', data: {id: paragraphId}});
},
+ clearAllParagraphOutput: function(noteId) {
+ websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_ALL_OUTPUT', data: {id: noteId}});
+ },
+
completion: function(paragraphId, buf, cursor) {
websocketEvents.sendNewEvent({
op: 'COMPLETION',
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-web/src/index.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/index.html b/zeppelin-web/src/index.html
index 4ffec03..0248c7c 100644
--- a/zeppelin-web/src/index.html
+++ b/zeppelin-web/src/index.html
@@ -185,6 +185,7 @@ limitations under the License.
<script src="components/searchService/search.service.js"></script>
<script src="components/login/login.controller.js"></script>
<script src="components/elasticInputCtrl/elasticInput.controller.js"></script>
+ <script src="components/noteAction/noteAction.service.js"></script>
<!-- endbuild -->
</body>
</html>
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
index 7ad2697..66362bd 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
@@ -327,6 +327,17 @@ public class Note implements Serializable, ParagraphJobListener {
}
/**
+ * Clear all paragraph output of note
+ */
+ public void clearAllParagraphOutput() {
+ synchronized (paragraphs) {
+ for (Paragraph p : paragraphs) {
+ p.setReturn(null, null);
+ }
+ }
+ }
+
+ /**
* Move paragraph into the new index (order from 0 ~ n-1).
*
* @param paragraphId ID of paragraph
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/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 d678661..b4da1e1 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
@@ -48,7 +48,7 @@ public class Message {
// @param id note id
CLONE_NOTE, // [c-s] clone new notebook
// @param id id of note to clone
- // @param name name fpor the cloned note
+ // @param name name for the cloned note
IMPORT_NOTE, // [c-s] import notebook
// @param object notebook
NOTE_UPDATE,
@@ -96,7 +96,8 @@ public class Message {
// @param notes serialized List<NoteInfo> object
PARAGRAPH_REMOVE,
- PARAGRAPH_CLEAR_OUTPUT,
+ PARAGRAPH_CLEAR_OUTPUT, // [c-s] clear output of paragraph
+ PARAGRAPH_CLEAR_ALL_OUTPUT, // [c-s] clear output of all paragraphs
PARAGRAPH_APPEND_OUTPUT, // [s-c] append output
PARAGRAPH_UPDATE_OUTPUT, // [s-c] update (replace) output
PING,
http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dd20e7bf/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
----------------------------------------------------------------------
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
index a077274..ed42144 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
@@ -19,6 +19,7 @@ package org.apache.zeppelin.notebook;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterFactory;
+import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.notebook.repo.NotebookRepo;
import org.apache.zeppelin.scheduler.Scheduler;
import org.apache.zeppelin.search.SearchService;
@@ -125,4 +126,23 @@ public class NoteTest {
assertNull(p2.getText());
}
+ @Test
+ public void clearAllParagraphOutputTest() {
+ when(interpreterFactory.getInterpreter(anyString(), anyString(), eq("md"))).thenReturn(interpreter);
+ when(interpreter.getScheduler()).thenReturn(scheduler);
+
+ Note note = new Note(repo, interpreterFactory, jobListenerFactory, index, credentials, noteEventListener);
+ Paragraph p1 = note.addParagraph();
+ InterpreterResult result = new InterpreterResult(InterpreterResult.Code.SUCCESS, InterpreterResult.Type.TEXT, "result");
+ p1.setResult(result);
+
+ Paragraph p2 = note.addParagraph();
+ p2.setReturn(result, new Throwable());
+
+ note.clearAllParagraphOutput();
+
+ assertNull(p1.getReturn());
+ assertNull(p2.getReturn());
+ }
+
}