Repository: zeppelin Updated Branches: refs/heads/master a47ff95ed -> dcf2c7a2c
[ZEPPELIN-2060] Make dynamic select form turn on or off using checkbox ### What is this PR for? I added "Auto Run" checkbox for select dynamic form to make user turn on / off automatic running after the form value changed. ### What type of PR is it? Improvement ### Todos * [x] - update docs after getting feedback ### What is the Jira issue? [ZEPPELIN-2060](https://issues.apache.org/jira/browse/ZEPPELIN-2060) ### How should this be tested? 1. Apply this patch and run Zeppelin web as dev mode ```bash # under zeppelin-web $ yarn run dev ``` 2. Go to Spark tutorial note and try to change value in select form as below screenshot imgs ### Screenshots (if appropriate) - "Auto Run" checkbox button will be shown only in select dynamic form's dropdown menu  - _**turn on**_ "Auto Run"-> auto run right after the value changed / _**turn off**_ -> need to press `Enter`  ### Questions: * Does the licenses files need update? no * Is there breaking changes for older versions? no * Does this needs documentation? yes, maybe [this part](https://github.com/apache/zeppelin/blob/master/docs/manual/dynamicform.md#select-form) Author: AhyoungRyu <fbdkdu...@hanmail.net> Closes #2100 from AhyoungRyu/feature/turnOnOrOffAutoRun and squashes the following commits: 4043579 [AhyoungRyu] Add 'setting: {forms: {}}' info to paragraphMock 47dcb5f [AhyoungRyu] Persist 'runOnSelectionChange' under note.json's config field 4904f38 [AhyoungRyu] Update dynamicForm docs 66c6c21 [AhyoungRyu] Add test case for behaviour of 'Run on selection change' 8a0ca30 [AhyoungRyu] Change label to 'Run on selection change' 5075711 [AhyoungRyu] Add a space next to checkbox f2e3259 [AhyoungRyu] Make dynamic select form turn on or off using checkbox Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/dcf2c7a2 Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/dcf2c7a2 Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/dcf2c7a2 Branch: refs/heads/master Commit: dcf2c7a2c86eef9411ccdf5d50b9851b89dd98b0 Parents: a47ff95 Author: AhyoungRyu <fbdkdu...@hanmail.net> Authored: Thu Mar 16 18:12:26 2017 +0900 Committer: ahyoungryu <ahyoung...@apache.org> Committed: Fri Mar 17 10:00:55 2017 +0900 ---------------------------------------------------------------------- .../img/screenshots/selectForm-checkbox.png | Bin 0 -> 9377 bytes docs/manual/dynamicform.md | 6 +++- .../integration/ParagraphActionsIT.java | 29 +++++++++++++++ .../notebook/paragraph/paragraph-control.html | 19 ++++++++-- .../paragraph-parameterizedQueryForm.html | 36 +++++++++++-------- .../notebook/paragraph/paragraph.controller.js | 18 +++++++++- .../paragraph/paragraph.controller.test.js | 5 ++- 7 files changed, 93 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/docs/assets/themes/zeppelin/img/screenshots/selectForm-checkbox.png ---------------------------------------------------------------------- diff --git a/docs/assets/themes/zeppelin/img/screenshots/selectForm-checkbox.png b/docs/assets/themes/zeppelin/img/screenshots/selectForm-checkbox.png new file mode 100644 index 0000000..47f9fa9 Binary files /dev/null and b/docs/assets/themes/zeppelin/img/screenshots/selectForm-checkbox.png differ http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/docs/manual/dynamicform.md ---------------------------------------------------------------------- diff --git a/docs/manual/dynamicform.md b/docs/manual/dynamicform.md index 12f51a9..b3ef4ed 100644 --- a/docs/manual/dynamicform.md +++ b/docs/manual/dynamicform.md @@ -56,7 +56,11 @@ Also you can separate option's display name and value, using `${formName=default <img src="../assets/themes/zeppelin/img/screenshots/form_select_displayname.png" /> -Hit enter after selecting option to run the paragraph with new value. +The paragraph will be automatically run after you change your selection by default. +But in case you have multiple select forms in one paragraph, you might want to run the paragraph after changing all the selections. +You can control this by unchecking the below **Run on selection change** option in the setting menu. Even if you uncheck this option, still you can run it by pressing `Enter`. + +<img src="../assets/themes/zeppelin/img/screenshots/selectForm-checkbox.png" /> ### Checkbox form http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java index 458b8d4..0507767 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java @@ -257,6 +257,35 @@ public class ParagraphActionsIT extends AbstractZeppelinIT { } @Test + public void testRunOnSelectionCheckbox() throws Exception { + if (!endToEndTestEnabled()) { + return; + } + try { + String xpathToCheckbox = getParagraphXPath(1) + "//ul/li/form/input[contains(@ng-checked, 'true')]"; + + createNewNote(); + + waitForParagraph(1, "READY"); + setTextOfParagraph(1, "%md My selection is ${my selection=1,1|2|3}"); + runParagraph(1); + + driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-settings']")).click(); + collector.checkThat("'Run on selection change' checkbox will be shown under dropdown menu ", + driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/form/input[contains(@ng-click, 'turnOnAutoRun(paragraph)')]")).isDisplayed(), + CoreMatchers.equalTo(true)); + + driver.findElement(By.xpath(xpathToCheckbox)).click(); + collector.checkThat("If 'Run on selection change' checkbox is unchecked, 'paragraph.config.runOnSelectionChange' will be false ", + driver.findElement(By.xpath(getParagraphXPath(1) + "//ul/li/span[contains(@ng-if, 'paragraph.config.runOnSelectionChange == false')]")).isDisplayed(), + CoreMatchers.equalTo(true)); + + } catch (Exception e) { + handleException("Exception in ParagraphActionsIT while testRunOnSelectionButton ", e); + } + } + + @Test public void testClearOutputButton() throws Exception { if (!endToEndTestEnabled()) { return; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html index 5f9c462..1411725 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html @@ -89,6 +89,19 @@ limitations under the License. </a> </li> <li role="separator" class="divider"></li> + <li style="padding-top:8px" + ng-if="paragraph.settings.forms[$root.keys(paragraph.settings.forms)].options && + paragraph.settings.forms[$root.keys(paragraph.settings.forms)].type != 'checkbox'"> + <span ng-if="paragraph.config.runOnSelectionChange == true" class="fa fa-toggle-on shortcut-icon" style="padding:3px 8px 8px 20px"></span> + <span ng-if="paragraph.config.runOnSelectionChange == false" class="fa fa-toggle-off shortcut-icon" style="padding:3px 8px 8px 20px"></span>Run on selection change + <form style="display:inline; float:right"> + <input type="checkbox" + style="width:16px; margin-right:20px" + tooltip-placement="top" tooltip="Even if you uncheck this, still can run the paragraph by pressing Enter" + ng-checked="{{paragraph.config.runOnSelectionChange}}" + ng-click="turnOnAutoRun(paragraph)"/> + </form> + </li> <li> <a ng-click="$event.stopPropagation()" class="dropdown"><span class="fa fa-arrows-h shortcut-icon"></span>Width <form style="display:inline; margin-left:5px; float:right"> @@ -100,15 +113,15 @@ limitations under the License. </a> </li> <li> - <a ng-click="moveUp(paragraph)" ng-hide="$first"><span class="icon-arrow-up shortcut-icon"></span>Move Up + <a ng-click="moveUp(paragraph)" ng-hide="$first"><span class="icon-arrow-up shortcut-icon"></span>Move up <span class="shortcut-keys">Ctrl+{{ isMac ? 'Option' : 'Alt'}}+k</span></a> </li> <li> - <a ng-click="moveDown(paragraph)" ng-hide="$last"><span class="icon-arrow-down shortcut-icon"></span>Move Down + <a ng-click="moveDown(paragraph)" ng-hide="$last"><span class="icon-arrow-down shortcut-icon"></span>Move down <span class="shortcut-keys">Ctrl+{{ isMac ? 'Option' : 'Alt'}}+j</span></a> </li> <li> - <a ng-click="insertNew('below')"><span class="icon-plus shortcut-icon"></span>Insert New + <a ng-click="insertNew('below')"><span class="icon-plus shortcut-icon"></span>Insert new <span class="shortcut-keys">Ctrl+{{ isMac ? 'Option' : 'Alt'}}+b</span></a> </li> <li> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/zeppelin-web/src/app/notebook/paragraph/paragraph-parameterizedQueryForm.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-parameterizedQueryForm.html b/zeppelin-web/src/app/notebook/paragraph/paragraph-parameterizedQueryForm.html index 65d13b7..7305440 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph-parameterizedQueryForm.html +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-parameterizedQueryForm.html @@ -19,33 +19,41 @@ limitations under the License. ng-init="loadForm(formulaire, paragraph.settings.params)"> <label class="control-label input-sm" ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }">{{formulaire.name}}</label> <div> - <input class="form-control input-sm" ng-if="!paragraph.settings.forms[formulaire.name].options" ng-enter="runParagraphFromButton(getEditorValue())" ng-model="paragraph.settings.params[formulaire.name]" ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }" name="{{formulaire.name}}" /> - + </div> + <div ng-if="paragraph.config.runOnSelectionChange == true"> <select class="form-control input-sm" ng-if="paragraph.settings.forms[formulaire.name].options && paragraph.settings.forms[formulaire.name].type != 'checkbox'" - ng-enter="runParagraphFromButton(getEditorValue())" + ng-change="runParagraphFromButton(getEditorValue())" ng-model="paragraph.settings.params[formulaire.name]" ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }" name="{{formulaire.name}}" ng-options="option.value as (option.displayName||option.value) for option in paragraph.settings.forms[formulaire.name].options"> </select> - - <div ng-if="paragraph.settings.forms[formulaire.name].type == 'checkbox'"> - <label ng-repeat="option in paragraph.settings.forms[formulaire.name].options" - class="checkbox-item input-sm"> - <input type="checkbox" - ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }" - ng-checked="paragraph.settings.params[formulaire.name].indexOf(option.value) > -1" - ng-click="toggleCheckbox(formulaire, option, false)"/>{{option.displayName||option.value}} - </label> - </div> - + </div> + <div ng-if="paragraph.config.runOnSelectionChange == false"> + <select class="form-control input-sm" + ng-if="paragraph.settings.forms[formulaire.name].options && paragraph.settings.forms[formulaire.name].type != 'checkbox'" + ng-enter="runParagraphFromButton(getEditorValue())" + ng-model="paragraph.settings.params[formulaire.name]" + ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }" + name="{{formulaire.name}}" + ng-options="option.value as (option.displayName||option.value) for option in paragraph.settings.forms[formulaire.name].options"> + </select> + </div> + <div ng-if="paragraph.settings.forms[formulaire.name].type == 'checkbox'"> + <label ng-repeat="option in paragraph.settings.forms[formulaire.name].options" + class="checkbox-item input-sm"> + <input type="checkbox" + ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }" + ng-checked="paragraph.settings.params[formulaire.name].indexOf(option.value) > -1" + ng-click="toggleCheckbox(formulaire, option, false)"/> {{option.displayName||option.value}} + </label> </div> </div> </form> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js index ab47d56..0f752fe 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js @@ -26,6 +26,7 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat 'ngInject'; var ANGULAR_FUNCTION_OBJECT_NAME_PREFIX = '_Z_ANGULAR_FUNC_'; + $rootScope.keys = Object.keys; $scope.parentNote = null; $scope.paragraph = {}; $scope.paragraph.results = {}; @@ -121,14 +122,24 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat }; var initializeDefault = function(config) { + var forms = $scope.paragraph.settings.forms; + if (!config.colWidth) { config.colWidth = 12; } - + if (config.enabled === undefined) { config.enabled = true; } + if (forms[Object.keys(forms)]) { + if (forms[Object.keys(forms)].options && forms[Object.keys(forms)].type !== 'checkbox') { + if (config.runOnSelectionChange === undefined) { + config.runOnSelectionChange = true; + } + } + } + if (!config.results) { config.results = {}; } @@ -377,6 +388,11 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat $scope.runParagraph(paragraphText, false, false) }; + $scope.turnOnAutoRun = function (paragraph) { + paragraph.config.runOnSelectionChange = !paragraph.config.runOnSelectionChange; + commitParagraph(paragraph); + }; + $scope.moveUp = function(paragraph) { $scope.$emit('moveParagraphUp', paragraph); }; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/dcf2c7a2/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js index 1aa4a4a..f8a1f63 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.test.js @@ -5,7 +5,10 @@ describe('Controller: ParagraphCtrl', function() { var scope; var websocketMsgSrvMock = {}; var paragraphMock = { - config: {} + config: {}, + settings: { + forms: {} + } }; var route = { current: {