ZEPPELIN-2528. Add a password text input to the ZeppelinContext

This commit is contained in:
Jeff Zhang 2018-06-22 14:37:17 +08:00
parent 5766c272b9
commit 084abd39c9
14 changed files with 162 additions and 24 deletions

View file

@ -73,7 +73,7 @@ matrix:
dist: trusty
addons:
firefox: "31.0"
env: BUILD_PLUGINS="true" CI="true" PYTHON="2" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop2 -Phelium-dev -Pexamples -Pintegration -Pscala-2.10" BUILD_FLAG="install -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl .,zeppelin-integration -DfailIfNoTests=false"
env: BUILD_PLUGINS="true" CI="true" PYTHON="2" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop2 -Phelium-dev -Pexamples -Pintegration -Pscala-2.10" BUILD_FLAG="install -DskipTests -DskipRat -pl ${INTERPRETERS}" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl zeppelin-integration -DfailIfNoTests=false"
# Test interpreter modules
- jdk: "oraclejdk8"

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -44,6 +44,15 @@ Also you can provide default value, using `${formName=defaultValue}`.
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/form_input_default.png" />
### Password form
To create password form, use `${password:formName}` templates.
for example
<img class="img-responsive" src="{{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/form_password.png" />
### Select form
To create select form, use `${formName=defaultValue,option1|option2...}`
@ -134,6 +143,27 @@ print("Hello "+z.textbox("name", "sun"))
</div>
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/form_input_default_prog.png" />
### Password form
<div class="codetabs">
<div data-lang="scala" markdown="1">
{% highlight scala %}
%spark
print("Password is "+ z.password("my_password"))
{% endhighlight %}
</div>
<div data-lang="python" markdown="1">
{% highlight python %}
%pyspark
print("Password is "+ z.password("my_password"))
{% endhighlight %}
</div>
</div>
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/form_password_prog.png" />
### Select form
<div class="codetabs">
<div data-lang="scala" markdown="1">

View file

@ -70,6 +70,9 @@ class PyZeppelinContext(object):
def textbox(self, name, defaultValue=""):
return self.z.textbox(name, defaultValue)
def password(self, name):
return self.z.password(name)
def noteTextbox(self, name, defaultValue=""):
return self.z.noteTextbox(name, defaultValue)

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.python;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
import org.apache.zeppelin.interpreter.Interpreter;
@ -240,6 +241,16 @@ public abstract class BasePythonInterpreterTest {
assertEquals("text_1", textbox.getName());
assertEquals("value_1", textbox.getDefaultValue());
// Password
context = getInterpreterContext();
result =
interpreter.interpret("z.password(name='pwd_1')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertTrue(context.getGui().getForms().get("pwd_1") instanceof Password);
Password password = (Password) context.getGui().getForms().get("pwd_1");
assertEquals("pwd_1", password.getName());
// Select
context = getInterpreterContext();
result = interpreter.interpret("z.select(name='select_1'," +

View file

@ -20,6 +20,7 @@ package org.apache.zeppelin.spark;
import com.google.common.io.Files;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
import org.apache.zeppelin.interpreter.Interpreter;
@ -215,6 +216,14 @@ public class NewSparkInterpreterTest {
assertEquals("name", textBox.getName());
assertEquals("default_name", textBox.getDefaultValue());
context = getInterpreterContext();
result = interpreter.interpret("z.password(\"pwd\")", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, context.getGui().getForms().size());
assertTrue(context.getGui().getForms().get("pwd") instanceof Password);
Password pwd = (Password) context.getGui().getForms().get("pwd");
assertEquals("pwd", pwd.getName());
context = getInterpreterContext();
result = interpreter.interpret("z.checkbox(\"checkbox_1\", Seq(\"value_2\"), Seq((\"value_1\", \"name_1\"), (\"value_2\", \"name_2\")))", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());

View file

@ -21,6 +21,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
@ -90,6 +91,11 @@ public class GUI implements Serializable {
return textbox(id, "");
}
public Object password(String id) {
forms.put(id, new Password(id));
return params.get(id);
}
public Object select(String id, Object defaultValue, ParamOption[] options) {
if (defaultValue == null && options != null && options.length > 0) {
defaultValue = options[0].getValue();

View file

@ -21,6 +21,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.OptionInput;
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
@ -49,6 +50,7 @@ public class Input<T> implements Serializable {
.registerSubtype(TextBox.class, "TextBox")
.registerSubtype(Select.class, "Select")
.registerSubtype(CheckBox.class, "CheckBox")
.registerSubtype(Password.class, "Password")
.registerSubtype(OldInput.OldTextBox.class, "input")
.registerSubtype(OldInput.OldSelect.class, "select")
.registerSubtype(OldInput.OldCheckBox.class, "checkbox")
@ -282,6 +284,8 @@ public class Input<T> implements Serializable {
}
} else if (type.equals("checkbox")) {
input = new CheckBox(varName, (Object[]) defaultValue, paramOptions);
} else if (type.equals("password")) {
input = new Password(varName);
} else {
throw new RuntimeException("Could not recognize dynamic form with type: " + type);
}

View file

@ -0,0 +1,36 @@
/*
* 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.display.ui;
import org.apache.zeppelin.display.Input;
public class Password extends Input<String> {
public Password() {
}
public Password(String name) {
this.name = name;
this.displayName = name;
this.defaultValue = "";
}
}

View file

@ -102,6 +102,20 @@ public abstract class BaseZeppelinContext {
return textbox(name, defaultValue, false);
}
@ZeppelinApi
public Object password(String name) {
return password(name, false);
}
@ZeppelinApi
public Object password(String name, boolean noteForm) {
if (noteForm) {
return noteGui.password(name);
} else {
return gui.password(name);
}
}
@ZeppelinApi
public Collection<Object> checkbox(String name, ParamOption[] options) {
return checkbox(name, options, false);

View file

@ -19,10 +19,9 @@ package org.apache.zeppelin.display;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
@ -35,14 +34,6 @@ import static org.junit.Assert.assertTrue;
public class InputTest {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testFormExtraction() {
// textbox form
@ -61,12 +52,21 @@ public class InputTest {
form = forms.get("input_form");
assertEquals("xxx", form.defaultValue);
assertTrue(form instanceof TextBox);
assertEquals("Input Form", form.getDisplayName());
// password form with display name
script = "${password:my_pwd(My Password)}";
forms = Input.extractSimpleQueryForm(script, false);
form = forms.get("my_pwd");
assertTrue(form instanceof Password);
assertEquals("My Password", form.getDisplayName());
// selection form
script = "${select_form(Selection Form)=op1,op1|op2(Option 2)|op3}";
form = Input.extractSimpleQueryForm(script, false).get("select_form");
assertEquals("select_form", form.name);
assertEquals("op1", form.defaultValue);
assertEquals("Selection Form", form.getDisplayName());
assertTrue(form instanceof Select);
assertArrayEquals(new ParamOption[]{
new ParamOption("op1", null),

View file

@ -499,6 +499,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
Note note = ZeppelinServer.notebook.createNote(anonymous);
Paragraph p = note.addNewParagraph(anonymous);
String code = "%spark.spark println(z.textbox(\"my_input\", \"default_name\"))\n" +
"println(z.password(\"my_pwd\"))\n" +
"println(z.select(\"my_select\", \"1\"," +
"Seq((\"1\", \"select_1\"), (\"2\", \"select_2\"))))\n" +
"val items=z.checkbox(\"my_checkbox\", Seq(\"2\"), " +
@ -510,17 +511,19 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
assertEquals(Status.FINISHED, p.getStatus());
Iterator<String> formIter = p.settings.getForms().keySet().iterator();
assert (formIter.next().equals("my_input"));
assert (formIter.next().equals("my_select"));
assert (formIter.next().equals("my_checkbox"));
assertEquals("my_input", formIter.next());
assertEquals("my_pwd", formIter.next());
assertEquals("my_select", formIter.next());
assertEquals("my_checkbox", formIter.next());
// check dynamic forms values
String[] result = p.getResult().message().get(0).getData().split("\n");
assertEquals(4, result.length);
assertEquals(5, result.length);
assertEquals("default_name", result[0]);
assertEquals("1", result[1]);
assertEquals("items: Seq[Object] = Buffer(2)", result[2]);
assertEquals("2", result[3]);
assertEquals("null", result[1]);
assertEquals("1", result[2]);
assertEquals("items: Seq[Object] = Buffer(2)", result[3]);
assertEquals("2", result[4]);
}
@Test
@ -528,6 +531,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
Note note = ZeppelinServer.notebook.createNote(anonymous);
Paragraph p = note.addNewParagraph(anonymous);
String code = "%spark.pyspark print(z.input('my_input', 'default_name'))\n" +
"print(z.password('my_pwd'))\n" +
"print(z.select('my_select', " +
"[('1', 'select_1'), ('2', 'select_2')], defaultValue='1'))\n" +
"items=z.checkbox('my_checkbox', " +
@ -538,16 +542,18 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
assertEquals(Status.FINISHED, p.getStatus());
Iterator<String> formIter = p.settings.getForms().keySet().iterator();
assert (formIter.next().equals("my_input"));
assert (formIter.next().equals("my_select"));
assert (formIter.next().equals("my_checkbox"));
assertEquals("my_input", formIter.next());
assertEquals("my_pwd", formIter.next());
assertEquals("my_select", formIter.next());
assertEquals("my_checkbox", formIter.next());
// check dynamic forms values
String[] result = p.getResult().message().get(0).getData().split("\n");
assertEquals(3, result.length);
assertEquals(4, result.length);
assertEquals("default_name", result[0]);
assertEquals("1", result[1]);
assertEquals("2", result[2]);
assertEquals("None", result[1]);
assertEquals("1", result[2]);
assertEquals("2", result[3]);
}
@Test

View file

@ -41,6 +41,25 @@ limitations under the License.
ng-class="{'disable': disable}"
name="{{formulaire.name}}" />
</div>
<div ng-if="actiononchange === true">
<input class="form-control input-sm"
ng-if="forms[formulaire.name].type == 'Password'"
ng-change="action()"
ng-model-options='{ debounce: 1000 }'
ng-model="params[formulaire.name]"
ng-class="{'disable': disable}"
type="password"
name="{{formulaire.name}}" />
</div>
<div ng-if="!actiononchange">
<input class="form-control input-sm"
ng-if="forms[formulaire.name].type == 'Password'"
ng-enter="action()"
ng-model="params[formulaire.name]"
ng-class="{'disable': disable}"
type="password"
name="{{formulaire.name}}" />
</div>
<div ng-if="actiononchange === true">
<select class="form-control input-sm"
ng-if="forms[formulaire.name].type == 'Select'"