This is an automated email from the ASF dual-hosted git repository. zjffdu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push: new 1979a0a [ZEPPELIN-3920] Paragraph support custom menu display with multiple URL link 1979a0a is described below commit 1979a0ac3a4b6e2b1c999f97796d8e59c62a047f Author: liuxunorg <33611...@qq.com> AuthorDate: Mon Jan 28 19:41:34 2019 +0800 [ZEPPELIN-3920] Paragraph support custom menu display with multiple URL link ### What is this PR for? Now the execution of the paragraph in zeppelin only supports the display of a single URL link, for example: Spark paragraph execution is a Spark JOB URL link. The machine learning task in the hadoop submarine needs to provide the user with a tensorflow Parameter server, a tensorflow worker server log link in YARN, and a tensorboard link, so a custom menu display that supports multiple URL links is now available. ### What type of PR is it? [Improvement] ### Todos * [x] Add testRuntimeInfos test cases in NotebookServerTest.java * [x] modify paragraph-control.html ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-3920 ### How should this be tested? [CI pass](https://travis-ci.org/liuxunorg/zeppelin/builds/472116016) ### Screenshots (if appropriate) ![alt text](https://github.com/liuxunorg/images/blob/master/zeppelin/multi-job-url.gif?raw=true "multi-job-url.gif") ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: liuxunorg <33611...@qq.com> Closes #3273 from liuxunorg/ZEPPELIN-3920 and squashes the following commits: 2c7e4bfe5 [liuxunorg] Fix single URL menu bug. 949ead1c6 [liuxunorg] [ZEPPELIN-3920] Paragraph support custom menu display with multiple URL links --- .../apache/zeppelin/socket/NotebookServerTest.java | 49 ++++++++++++++++++++++ .../app/notebook/paragraph/paragraph-control.html | 23 +++------- .../org/apache/zeppelin/notebook/Paragraph.java | 2 +- .../zeppelin/notebook/ParagraphRuntimeInfo.java | 18 ++++++-- 4 files changed, 69 insertions(+), 23 deletions(-) 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 ab805b8..08bed2f 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 @@ -35,6 +35,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; +import java.util.Map; import javax.inject.Provider; import javax.servlet.http.HttpServletRequest; import org.apache.zeppelin.conf.ZeppelinConfiguration; @@ -419,6 +420,54 @@ public class NotebookServerTest extends AbstractTestRestApi { notebook.removeNote(createdNote.getId(), anonymous); } + @Test + public void testRuntimeInfos() { + // mock note + String msg = "{\"op\":\"IMPORT_NOTE\",\"data\":" + + "{\"note\":{\"paragraphs\": [{\"text\": \"Test " + + "paragraphs import\"," + "\"progressUpdateIntervalMs\":500," + + "\"config\":{},\"settings\":{}}]," + + "\"name\": \"Test Zeppelin notebook import\",\"config\": " + + "{}}}}"; + Message messageReceived = notebookServer.deserializeMessage(msg); + Note note = null; + try { + note = notebookServer.importNote(null, messageReceived); + } catch (NullPointerException e) { + //broadcastNoteList(); failed nothing to worry. + LOG.error("Exception in NotebookServerTest while testImportNotebook, failed nothing to " + + "worry ", e); + } catch (IOException e) { + e.printStackTrace(); + } + + assertNotEquals(null, notebook.getNote(note.getId())); + assertNotEquals(null, note.getParagraph(0)); + + String nodeId = note.getId(); + String paragraphId = note.getParagraph(0).getId(); + + // update RuntimeInfos + Map<String, String> infos = new java.util.HashMap<>(); + infos.put("jobUrl", "jobUrl_value"); + infos.put("jobLabel", "jobLabel_value"); + infos.put("label", "SPARK JOB"); + infos.put("tooltip", "View in Spark web UI"); + infos.put("noteId", nodeId); + infos.put("paraId", paragraphId); + + notebookServer.onParaInfosReceived(nodeId, paragraphId, "spark", infos); + Paragraph paragraph = note.getParagraph(paragraphId); + + // check RuntimeInfos + assertTrue(paragraph.getRuntimeInfos().containsKey("jobUrl")); + List<Map<String, String>> list = paragraph.getRuntimeInfos().get("jobUrl").getValue(); + assertEquals(1, list.size()); + assertEquals(2, list.get(0).size()); + assertEquals(list.get(0).get("jobUrl"), "jobUrl_value"); + assertEquals(list.get(0).get("jobLabel"), "jobLabel_value"); + } + private NotebookSocket createWebSocket() { NotebookSocket sock = mock(NotebookSocket.class); when(sock.getRequest()).thenReturn(mockRequest); diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html index 4ef430f..b39ac08 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html @@ -15,7 +15,7 @@ limitations under the License. <div id="{{paragraph.id}}_control" class="control" ng-show="!asIframe"> <span> <span ng-show="paragraph.runtimeInfos.jobUrl.values.length == 1"> - <a href="{{paragraph.runtimeInfos.jobUrl.values[0]}}" target="_blank" style="text-decoration: none;" + <a href="{{paragraph.runtimeInfos.jobUrl.jobUrl}}" target="_blank" style="text-decoration: none;" tooltip-placement="top" uib-tooltip="{{paragraph.runtimeInfos.jobUrl.tooltip}}" > <span class="fa fa-tasks"></span> {{paragraph.runtimeInfos.jobUrl.label}} @@ -25,11 +25,12 @@ limitations under the License. <span style="cursor:pointer;color:#3071A9" tooltip-placement="top" uib-tooltip="{{paragraph.runtimeInfos.jobUrl.tooltip}}" data-toggle="dropdown" type="button"> <span class="fa fa-tasks"></span> - {{paragraph.runtimeInfos.jobUrl.label}}S + {{paragraph.runtimeInfos.jobUrl.label}} </span> <ul class="dropdown-menu" role="menu" style="width:200px;z-index:1002"> - <li ng-class="{'option-disabled': !noteOperationsAllowed()}" ng-repeat="url in paragraph.runtimeInfos.jobUrl.values"> - <a href="{{url}}" target="_blank"><span class="fa fa-external-link-square"></span> Jobs #{{$index}}</a> + <li ng-class="{'option-disabled': !noteOperationsAllowed()}" ng-repeat="value in paragraph.runtimeInfos.jobUrl.values"> + <a ng-if="value.jobLabel === undefined" href="{{value['jobUrl']}}" target="_blank"><span class="fa fa-external-link-square"></span> Jobs #{{$index}}</a> + <a ng-if="value.jobLabel !== undefined" href="{{value['jobUrl']}}" target="_blank"><span class="fa fa-external-link-square"></span> {{value['jobLabel']}} </a> </li> </ul> </span> @@ -54,20 +55,6 @@ limitations under the License. ng-click="cancelParagraph(paragraph)" ng-class="{'item-disable' : isNoteRunning}" ng-show="paragraph.status=='RUNNING' || paragraph.status=='PENDING'"></span> - <span ng-show="paragraph.runtimeInfos.jobUrl.length == 1"> - <a href="{{paragraph.runtimeInfos.jobUrl[0]}}" target="_blank"><span class="fa fa-tasks"></span> Spark job </a> - </span> - <span class="dropdown" ng-show="paragraph.runtimeInfos.jobUrl.length > 1"> - <span class="fa fa-tasks" style="cursor:pointer;color:#3071A9" tooltip-placement="top" uib-tooltip="Run this paragraph (Shift+Enter)" - data-toggle="dropdown" - type="button"> Spark Jobs - </span> - <ul class="dropdown-menu" role="menu" style="width:200px;z-index:1002"> - <li ng-class="{'option-disabled': !noteOperationsAllowed()}" ng-repeat="url in paragraph.runtimeInfos.jobUrl"> - <a href="{{url}}" target="_blank"><span class="fa fa-external-link-square"></span> Jobs #{{$index}}</a> - </li> - </ul> - </span> <span class="{{paragraph.config.editorHide ? 'icon-size-fullscreen' : 'icon-size-actual'}}" style="cursor:pointer" tooltip-placement="top" uib-tooltip="{{(paragraph.config.editorHide ? 'Show' : 'Hide')}} editor (Ctrl+{{ (isMac ? 'Option' : 'Alt') }}+E)" ng-click="toggleEditor(paragraph)"></span> diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index bd3104f..ce78230 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -655,7 +655,7 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen info = new ParagraphRuntimeInfo(key, label, tooltip, group, intpSettingId); this.runtimeInfos.put(key, info); } - info.addValue(infos.get(key)); + info.addValue(infos); } } } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphRuntimeInfo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphRuntimeInfo.java index 0042023..23ce9e8 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphRuntimeInfo.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/ParagraphRuntimeInfo.java @@ -1,19 +1,24 @@ package org.apache.zeppelin.notebook; +import com.google.common.annotations.VisibleForTesting; + import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Store runtime infos of each para * */ public class ParagraphRuntimeInfo { - private String propertyName; // Name of the property private String label; // Label to be used in UI private String tooltip; // Tooltip text toshow in UI private String group; // The interpretergroup from which the info was derived - private List<String> values; // values for the property + + // runtimeInfos job url or dropdown-menu key in + // zeppelin-web/src/app/notebook/paragraph/paragraph-control.html + private List<Map<String, String>> values; // values for the key-value pair property private String interpreterSettingId; public ParagraphRuntimeInfo(String propertyName, String label, @@ -29,8 +34,13 @@ public class ParagraphRuntimeInfo { this.values = new ArrayList<>(); } - public void addValue(String value) { - values.add(value); + public void addValue(Map<String, String> mapValue) { + values.add(mapValue); + } + + @VisibleForTesting + public List<Map<String, String>> getValue() { + return values; } public String getInterpreterSettingId() {