mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
ZEPPELIN-2395. Refactor Input.java to make dynamic forms extensible
This commit is contained in:
parent
4b1b521fc3
commit
16d42a848e
29 changed files with 791 additions and 156 deletions
1
LICENSE
1
LICENSE
|
|
@ -255,6 +255,7 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
|
|||
(Apache 2.0) Bootstrap v3.0.2 (http://getbootstrap.com/) - https://github.com/twbs/bootstrap/blob/v3.0.2/LICENSE
|
||||
(Apache 2.0) Software under ./bigquery/* was developed at Google (http://www.google.com/). Licensed under the Apache v2.0 License.
|
||||
(Apache 2.0) Roboto Font (https://github.com/google/roboto/)
|
||||
(Apache 2.0) Gson extra (https://github.com/DanySK/gson-extras)
|
||||
|
||||
========================================================================
|
||||
BSD 3-Clause licenses
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import com.datastax.driver.core.exceptions.DriverException
|
|||
import com.datastax.driver.core.policies.{LoggingRetryPolicy, FallthroughRetryPolicy, DowngradingConsistencyRetryPolicy, Policies}
|
||||
import org.apache.zeppelin.cassandra.TextBlockHierarchy._
|
||||
import org.apache.zeppelin.display.AngularObjectRegistry
|
||||
import org.apache.zeppelin.display.Input.ParamOption
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code
|
||||
import org.apache.zeppelin.interpreter.{InterpreterException, InterpreterResult, InterpreterContext}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import com.datastax.driver.core.Statement;
|
|||
|
||||
import org.apache.zeppelin.display.AngularObjectRegistry;
|
||||
import org.apache.zeppelin.display.GUI;
|
||||
import org.apache.zeppelin.display.Input.ParamOption;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
import org.junit.Rule;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import org.apache.zeppelin.interpreter.InterpreterContextRunner;
|
|||
import org.apache.zeppelin.display.AngularObjectRegistry;
|
||||
import org.apache.zeppelin.display.AngularObject;
|
||||
import org.apache.zeppelin.display.GUI;
|
||||
import org.apache.zeppelin.display.Input.ParamOption;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
import org.apache.zeppelin.annotation.ZeppelinApi;
|
||||
import org.apache.zeppelin.interpreter.RemoteWorksController;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
|
|
|
|||
7
pom.xml
7
pom.xml
|
|
@ -93,6 +93,7 @@
|
|||
<log4j.version>1.2.17</log4j.version>
|
||||
<libthrift.version>0.9.2</libthrift.version>
|
||||
<gson.version>2.2</gson.version>
|
||||
<gson-extras.version>0.2.1</gson-extras.version>
|
||||
<guava.version>15.0</guava.version>
|
||||
<jetty.version>9.2.15.v20160210</jetty.version>
|
||||
<httpcomponents.core.version>4.3.3</httpcomponents.core.version>
|
||||
|
|
@ -192,6 +193,12 @@
|
|||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.danilopianini</groupId>
|
||||
<artifactId>gson-extras</artifactId>
|
||||
<version>${gson-extras.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class PyZeppelinContext(object):
|
|||
|
||||
def __init__(self, z):
|
||||
self.z = z
|
||||
self.paramOption = gateway.jvm.org.apache.zeppelin.display.Input.ParamOption
|
||||
self.paramOption = gateway.jvm.org.apache.zeppelin.display.ui.OptionInput.ParamOption
|
||||
self.javaList = gateway.jvm.java.util.ArrayList
|
||||
self.max_result = 1000
|
||||
self._displayhook = lambda *args: None
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import org.apache.zeppelin.display.AngularObject;
|
|||
import org.apache.zeppelin.display.AngularObjectRegistry;
|
||||
import org.apache.zeppelin.display.AngularObjectWatcher;
|
||||
import org.apache.zeppelin.display.GUI;
|
||||
import org.apache.zeppelin.display.Input.ParamOption;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContextRunner;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
|
|
@ -114,14 +114,33 @@ public class ZeppelinContext {
|
|||
public SQLContext sqlContext;
|
||||
private GUI gui;
|
||||
|
||||
/**
|
||||
* @deprecated use z.textbox instead
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
@ZeppelinApi
|
||||
public Object input(String name) {
|
||||
return input(name, "");
|
||||
return textbox(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use z.textbox instead
|
||||
*/
|
||||
@Deprecated
|
||||
@ZeppelinApi
|
||||
public Object input(String name, Object defaultValue) {
|
||||
return textbox(name, defaultValue.toString());
|
||||
}
|
||||
|
||||
@ZeppelinApi
|
||||
public Object input(String name, Object defaultValue) {
|
||||
return gui.input(name, defaultValue);
|
||||
public Object textbox(String name) {
|
||||
return textbox(name, "");
|
||||
}
|
||||
|
||||
@ZeppelinApi
|
||||
public Object textbox(String name, String defaultValue) {
|
||||
return gui.textbox(name, defaultValue);
|
||||
}
|
||||
|
||||
@ZeppelinApi
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@
|
|||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.danilopianini</groupId>
|
||||
<artifactId>gson-extras</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-exec</artifactId>
|
||||
|
|
|
|||
|
|
@ -17,17 +17,27 @@
|
|||
|
||||
package org.apache.zeppelin.display;
|
||||
|
||||
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.Select;
|
||||
import org.apache.zeppelin.display.ui.TextBox;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.zeppelin.display.Input.ParamOption;
|
||||
|
||||
/**
|
||||
* Settings of a form.
|
||||
*/
|
||||
public class GUI implements Serializable {
|
||||
|
||||
private static Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(Input.TypeAdapterFactory)
|
||||
.create();
|
||||
|
||||
Map<String, Object> params = new HashMap<>(); // form parameters from client
|
||||
LinkedHashMap<String, Input> forms = new LinkedHashMap<>(); // form configuration
|
||||
|
||||
|
|
@ -51,19 +61,29 @@ public class GUI implements Serializable {
|
|||
this.forms = forms;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Object input(String id) {
|
||||
return textbox(id, "");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Object input(String id, Object defaultValue) {
|
||||
return textbox(id, defaultValue.toString());
|
||||
}
|
||||
|
||||
public Object textbox(String id, String defaultValue) {
|
||||
// first find values from client and then use default
|
||||
Object value = params.get(id);
|
||||
if (value == null) {
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
forms.put(id, new Input(id, defaultValue, "input"));
|
||||
forms.put(id, new TextBox(id, defaultValue));
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object input(String id) {
|
||||
return input(id, "");
|
||||
public Object textbox(String id) {
|
||||
return textbox(id, "");
|
||||
}
|
||||
|
||||
public Object select(String id, Object defaultValue, ParamOption[] options) {
|
||||
|
|
@ -71,7 +91,7 @@ public class GUI implements Serializable {
|
|||
if (value == null) {
|
||||
value = defaultValue;
|
||||
}
|
||||
forms.put(id, new Input(id, defaultValue, "select", options));
|
||||
forms.put(id, new Select(id, defaultValue, options));
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +101,7 @@ public class GUI implements Serializable {
|
|||
if (checked == null) {
|
||||
checked = defaultChecked;
|
||||
}
|
||||
forms.put(id, new Input(id, defaultChecked, "checkbox", options));
|
||||
forms.put(id, new CheckBox(id, defaultChecked, options));
|
||||
List<Object> filtered = new LinkedList<>();
|
||||
for (Object o : checked) {
|
||||
if (isValidOption(o, options)) {
|
||||
|
|
@ -103,4 +123,41 @@ public class GUI implements Serializable {
|
|||
public void clear() {
|
||||
this.forms = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
public void convertOldInput() {
|
||||
for (Map.Entry<String, Input> entry : forms.entrySet()) {
|
||||
if (entry.getValue() instanceof OldInput) {
|
||||
Input convertedInput = convertFromOldInput((OldInput) entry.getValue());
|
||||
forms.put(entry.getKey(), convertedInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static GUI fromJson(String json) {
|
||||
GUI gui = gson.fromJson(json, GUI.class);
|
||||
gui.convertOldInput();
|
||||
return gui;
|
||||
}
|
||||
|
||||
private Input convertFromOldInput(OldInput oldInput) {
|
||||
Input convertedInput = null;
|
||||
|
||||
if (oldInput.options == null || oldInput instanceof OldInput.OldTextBox) {
|
||||
convertedInput = new TextBox(oldInput.name, oldInput.defaultValue.toString());
|
||||
} else if (oldInput instanceof OldInput.OldCheckBox) {
|
||||
convertedInput = new CheckBox(oldInput.name, (List) oldInput.defaultValue, oldInput.options);
|
||||
} else if (oldInput instanceof OldInput && oldInput.options != null) {
|
||||
convertedInput = new Select(oldInput.name, oldInput.defaultValue, oldInput.options);
|
||||
} else {
|
||||
throw new RuntimeException("Can not convert this OldInput.");
|
||||
}
|
||||
convertedInput.setDisplayName(oldInput.getDisplayName());
|
||||
convertedInput.setHidden(oldInput.isHidden());
|
||||
convertedInput.setArgument(oldInput.getArgument());
|
||||
return convertedInput;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
package org.apache.zeppelin.display;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.zeppelin.display.ui.*;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
|
@ -25,105 +27,43 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Input type.
|
||||
* Base class for dynamic forms. Also used as factory class of dynamic forms.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class Input implements Serializable {
|
||||
/**
|
||||
* Parameters option.
|
||||
*/
|
||||
public static class ParamOption {
|
||||
Object value;
|
||||
String displayName;
|
||||
public class Input<T> implements Serializable {
|
||||
|
||||
public ParamOption(Object value, String displayName) {
|
||||
super();
|
||||
this.value = value;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
// @TODO(zjffdu). Use gson's RuntimeTypeAdapterFactory and remove the old input form support
|
||||
// in future.
|
||||
public static final RuntimeTypeAdapterFactory TypeAdapterFactory =
|
||||
RuntimeTypeAdapterFactory.of(Input.class, "type")
|
||||
.registerSubtype(TextBox.class, "TextBox")
|
||||
.registerSubtype(Select.class, "Select")
|
||||
.registerSubtype(CheckBox.class, "CheckBox")
|
||||
.registerSubtype(OldInput.OldTextBox.class, "input")
|
||||
.registerSubtype(OldInput.OldSelect.class, "select")
|
||||
.registerSubtype(OldInput.OldCheckBox.class, "checkbox")
|
||||
.registerSubtype(OldInput.class, null);
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ParamOption that = (ParamOption) o;
|
||||
|
||||
if (value != null ? !value.equals(that.value) : that.value != null) return false;
|
||||
return displayName != null ? displayName.equals(that.displayName) : that.displayName == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = value != null ? value.hashCode() : 0;
|
||||
result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
protected String name;
|
||||
protected String displayName;
|
||||
protected T defaultValue;
|
||||
protected boolean hidden;
|
||||
protected String argument;
|
||||
|
||||
public Input() {
|
||||
}
|
||||
|
||||
String name;
|
||||
String displayName;
|
||||
String type;
|
||||
String argument;
|
||||
Object defaultValue;
|
||||
ParamOption[] options;
|
||||
boolean hidden;
|
||||
|
||||
public Input(String name, Object defaultValue, String type) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Input(String name, Object defaultValue, String type, ParamOption[] options) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
this.type = type;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public Input(String name, String displayName, String type, String argument, Object defaultValue,
|
||||
ParamOption[] options, boolean hidden) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.argument = argument;
|
||||
this.type = type;
|
||||
this.defaultValue = defaultValue;
|
||||
this.options = options;
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return name.equals(((Input) o).getName());
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
|
|
@ -134,41 +74,37 @@ public class Input implements Serializable {
|
|||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
public void setArgument(String argument) {
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
public void setHidden(boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
public String getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
public static TextBox textbox(String name, String defaultValue) {
|
||||
return new TextBox(name, defaultValue);
|
||||
}
|
||||
|
||||
public ParamOption[] getOptions() {
|
||||
return options;
|
||||
public static Select select(String name, Object defaultValue, ParamOption[] options) {
|
||||
return new Select(name, defaultValue, options);
|
||||
}
|
||||
|
||||
public void setOptions(ParamOption[] options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
public static CheckBox checkbox(String name, Object[] defaultChecked, ParamOption[] options) {
|
||||
return new CheckBox(name, defaultChecked, options);
|
||||
}
|
||||
|
||||
// Syntax of variables: ${TYPE:NAME=DEFAULT_VALUE1|DEFAULT_VALUE2|...,VALUE1|VALUE2|...}
|
||||
// Type is optional. Type may contain an optional argument with syntax: TYPE(ARG)
|
||||
// NAME and VALUEs may contain an optional display name with syntax: NAME(DISPLAY_NAME)
|
||||
// DEFAULT_VALUEs may not contain display name
|
||||
// Examples: ${age} input form without default value
|
||||
// ${age=3} input form with default value
|
||||
// ${age(Age)=3} input form with display name and default value
|
||||
// Examples: ${age} textbox form without default value
|
||||
// ${age=3} textbox form with default value
|
||||
// ${age(Age)=3} textbox form with display name and default value
|
||||
// ${country=US(United States)|UK|JP} select form with
|
||||
// ${checkbox( or ):country(Country)=US|JP,US(United States)|UK|JP}
|
||||
// checkbox form with " or " as delimiter: will be
|
||||
|
|
@ -282,7 +218,22 @@ public class Input implements Serializable {
|
|||
|
||||
}
|
||||
|
||||
return new Input(varName, displayName, type, arg, defaultValue, paramOptions, hidden);
|
||||
Input input = null;
|
||||
if (type == null) {
|
||||
if (paramOptions == null) {
|
||||
input = new TextBox(varName, (String) defaultValue);
|
||||
} else {
|
||||
input = new Select(varName, defaultValue, paramOptions);
|
||||
}
|
||||
} else if (type.equals("checkbox")) {
|
||||
input = new CheckBox(varName, (Object[]) defaultValue, paramOptions);
|
||||
} else {
|
||||
throw new RuntimeException("Could not recognize dynamic form with type: " + type);
|
||||
}
|
||||
input.setArgument(arg);
|
||||
input.setDisplayName(displayName);
|
||||
input.setHidden(hidden);
|
||||
return input;
|
||||
}
|
||||
|
||||
public static LinkedHashMap<String, Input> extractSimpleQueryForm(String script) {
|
||||
|
|
@ -314,11 +265,12 @@ public class Input implements Serializable {
|
|||
if (params.containsKey(input.name)) {
|
||||
value = params.get(input.name);
|
||||
} else {
|
||||
value = input.defaultValue;
|
||||
value = input.getDefaultValue();
|
||||
}
|
||||
|
||||
String expanded;
|
||||
if (value instanceof Object[] || value instanceof Collection) { // multi-selection
|
||||
OptionInput optionInput = (OptionInput) input;
|
||||
String delimiter = input.argument;
|
||||
if (delimiter == null) {
|
||||
delimiter = DEFAULT_DELIMITER;
|
||||
|
|
@ -327,7 +279,7 @@ public class Input implements Serializable {
|
|||
: Arrays.asList((Object[]) value);
|
||||
List<Object> validChecked = new LinkedList<>();
|
||||
for (Object o : checked) { // filter out obsolete checked values
|
||||
for (ParamOption option : input.getOptions()) {
|
||||
for (ParamOption option : optionInput.getOptions()) {
|
||||
if (option.getValue().equals(o)) {
|
||||
validChecked.add(o);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
|
||||
/**
|
||||
* Old Input type.
|
||||
* The reason I still keep Old Input is for compatibility. There's one bug in the old input forms.
|
||||
* There's 2 ways to create input forms: frontend & backend.
|
||||
* The bug is in frontend. The type would not be set correctly when input form
|
||||
* is created in frontend (Input.getInputForm).
|
||||
*/
|
||||
public class OldInput extends Input<Object> {
|
||||
|
||||
ParamOption[] options;
|
||||
|
||||
public OldInput() {}
|
||||
|
||||
public OldInput(String name, Object defaultValue) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public OldInput(String name, Object defaultValue, ParamOption[] options) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return name.equals(((OldInput) o).getName());
|
||||
}
|
||||
|
||||
public ParamOption[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(ParamOption[] options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static class OldTextBox extends OldInput {
|
||||
public OldTextBox(String name, Object defaultValue) {
|
||||
super(name, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static class OldSelect extends OldInput {
|
||||
public OldSelect(String name, Object defaultValue, ParamOption[] options) {
|
||||
super(name, defaultValue, options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static class OldCheckBox extends OldInput {
|
||||
public OldCheckBox(String name, Object defaultValue, ParamOption[] options) {
|
||||
super(name, defaultValue, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Copied from gson with minor changes to support old input forms
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
|
||||
private final Class<?> baseType;
|
||||
private final String typeFieldName;
|
||||
private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<String, Class<?>>();
|
||||
private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<Class<?>, String>();
|
||||
|
||||
private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName) {
|
||||
if (typeFieldName == null || baseType == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.baseType = baseType;
|
||||
this.typeFieldName = typeFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime type adapter using for {@code baseType} using {@code
|
||||
* typeFieldName} as the type field name. Type field names are case sensitive.
|
||||
*/
|
||||
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) {
|
||||
return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime type adapter for {@code baseType} using {@code "type"} as
|
||||
* the type field name.
|
||||
*/
|
||||
public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) {
|
||||
return new RuntimeTypeAdapterFactory<T>(baseType, "type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@code type} identified by {@code label}. Labels are case
|
||||
* sensitive.
|
||||
*
|
||||
* @throws IllegalArgumentException if either {@code type} or {@code label}
|
||||
* have already been registered on this type adapter.
|
||||
*/
|
||||
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) {
|
||||
if (type == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {
|
||||
throw new IllegalArgumentException("types and labels must be unique");
|
||||
}
|
||||
labelToSubtype.put(label, type);
|
||||
subtypeToLabel.put(type, label);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@code type} identified by its {@link Class#getSimpleName simple
|
||||
* name}. Labels are case sensitive.
|
||||
*
|
||||
* @throws IllegalArgumentException if either {@code type} or its simple name
|
||||
* have already been registered on this type adapter.
|
||||
*/
|
||||
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
|
||||
return registerSubtype(type, type.getSimpleName());
|
||||
}
|
||||
|
||||
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
|
||||
if (type.getRawType() != baseType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<String, TypeAdapter<?>>();
|
||||
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate =
|
||||
new LinkedHashMap<Class<?>, TypeAdapter<?>>();
|
||||
for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) {
|
||||
TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
|
||||
labelToDelegate.put(entry.getKey(), delegate);
|
||||
subtypeToDelegate.put(entry.getValue(), delegate);
|
||||
}
|
||||
|
||||
return new TypeAdapter<R>() {
|
||||
@Override public R read(JsonReader in) throws IOException {
|
||||
JsonElement jsonElement = Streams.parse(in);
|
||||
JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
|
||||
String label = (labelJsonElement == null ? null : labelJsonElement.getAsString());
|
||||
@SuppressWarnings("unchecked") // registration requires that subtype extends T
|
||||
TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
|
||||
if (delegate == null) {
|
||||
throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
|
||||
+ label + "; did you forget to register a subtype?");
|
||||
}
|
||||
return delegate.fromJsonTree(jsonElement);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter out, R value) throws IOException {
|
||||
Class<?> srcType = value.getClass();
|
||||
String label = subtypeToLabel.get(srcType);
|
||||
@SuppressWarnings("unchecked") // registration requires that subtype extends T
|
||||
TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);
|
||||
if (delegate == null) {
|
||||
throw new JsonParseException("cannot serialize " + srcType.getName()
|
||||
+ "; did you forget to register a subtype?");
|
||||
}
|
||||
JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
|
||||
if (jsonObject.has(typeFieldName) && !srcType.getSimpleName().equals("OldInput")) {
|
||||
throw new JsonParseException("cannot serialize " + srcType.getName()
|
||||
+ " because it already defines a field named " + typeFieldName);
|
||||
}
|
||||
JsonObject clone = new JsonObject();
|
||||
if (!srcType.getSimpleName().equals("OldInput")) {
|
||||
clone.add(typeFieldName, new JsonPrimitive(label));
|
||||
}
|
||||
for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {
|
||||
clone.add(e.getKey(), e.getValue());
|
||||
}
|
||||
Streams.write(clone, out);
|
||||
}
|
||||
}.nullSafe();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Html Checkbox
|
||||
*/
|
||||
public class CheckBox extends OptionInput<Object[]> {
|
||||
|
||||
public CheckBox() {
|
||||
}
|
||||
|
||||
public CheckBox(String name, Object[] defaultValue, ParamOption[] options) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public CheckBox(String name, Collection<Object> defaultValue, ParamOption[] options) {
|
||||
this(name, defaultValue.toArray(), options);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Base class for Input with options
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class OptionInput<T> extends Input<T> {
|
||||
|
||||
/**
|
||||
* Parameters option.
|
||||
*/
|
||||
public static class ParamOption {
|
||||
Object value;
|
||||
String displayName;
|
||||
|
||||
public ParamOption(Object value, String displayName) {
|
||||
super();
|
||||
this.value = value;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ParamOption that = (ParamOption) o;
|
||||
|
||||
if (value != null ? !value.equals(that.value) : that.value != null) return false;
|
||||
return displayName != null ? displayName.equals(that.displayName) : that.displayName == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = value != null ? value.hashCode() : 0;
|
||||
result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected ParamOption[] options;
|
||||
|
||||
public ParamOption[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* Html Dropdown list
|
||||
*/
|
||||
public class Select extends OptionInput<Object> {
|
||||
|
||||
public Select() {
|
||||
|
||||
}
|
||||
|
||||
public Select(String name, Object defaultValue, ParamOption[] options) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Html TextBox control
|
||||
*/
|
||||
public class TextBox extends Input<String> {
|
||||
|
||||
public TextBox() {
|
||||
|
||||
}
|
||||
|
||||
public TextBox(String name, String defaultValue) {
|
||||
this.name = name;
|
||||
this.displayName = name;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -381,14 +381,14 @@ public class RemoteInterpreter extends Interpreter {
|
|||
context.getConfig().putAll(remoteConfig);
|
||||
|
||||
if (form == FormType.NATIVE) {
|
||||
GUI remoteGui = gson.fromJson(remoteResult.getGui(), GUI.class);
|
||||
GUI remoteGui = GUI.fromJson(remoteResult.getGui());
|
||||
currentGUI.clear();
|
||||
currentGUI.setParams(remoteGui.getParams());
|
||||
currentGUI.setForms(remoteGui.getForms());
|
||||
} else if (form == FormType.SIMPLE) {
|
||||
final Map<String, Input> currentForms = currentGUI.getForms();
|
||||
final Map<String, Object> currentParams = currentGUI.getParams();
|
||||
final GUI remoteGUI = gson.fromJson(remoteResult.getGui(), GUI.class);
|
||||
final GUI remoteGUI = GUI.fromJson(remoteResult.getGui());
|
||||
final Map<String, Input> remoteForms = remoteGUI.getForms();
|
||||
final Map<String, Object> remoteParams = remoteGUI.getParams();
|
||||
currentForms.putAll(remoteForms);
|
||||
|
|
|
|||
|
|
@ -592,7 +592,7 @@ public class RemoteInterpreterServer
|
|||
gson.fromJson(ric.getAuthenticationInfo(), AuthenticationInfo.class),
|
||||
(Map<String, Object>) gson.fromJson(ric.getConfig(),
|
||||
new TypeToken<Map<String, Object>>() {}.getType()),
|
||||
gson.fromJson(ric.getGui(), GUI.class),
|
||||
GUI.fromJson(ric.getGui()),
|
||||
interpreterGroup.getAngularObjectRegistry(),
|
||||
interpreterGroup.getResourcePool(),
|
||||
contextRunners, output, remoteWorksController, eventClient);
|
||||
|
|
@ -737,7 +737,7 @@ public class RemoteInterpreterServer
|
|||
result.code().name(),
|
||||
msg,
|
||||
gson.toJson(config),
|
||||
gson.toJson(gui));
|
||||
gui.toJson());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.zeppelin.display.ui.CheckBox;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
import org.apache.zeppelin.display.ui.Select;
|
||||
import org.apache.zeppelin.display.ui.TextBox;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class GUITest {
|
||||
|
||||
private ParamOption[] options = new ParamOption[]{
|
||||
new ParamOption("1", "value_1"),
|
||||
new ParamOption("2", "value_2")
|
||||
};
|
||||
|
||||
private List<Object> checkedItems;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
checkedItems = new ArrayList<>();
|
||||
checkedItems.add("1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGson() {
|
||||
GUI gui = new GUI();
|
||||
gui.textbox("textbox_1", "default_text_1");
|
||||
gui.select("select_1", "1", options);
|
||||
List<Object> list = new ArrayList();
|
||||
list.add("1");
|
||||
gui.checkbox("checkbox_1", list, options);
|
||||
|
||||
String json = gui.toJson();
|
||||
System.out.println(json);
|
||||
GUI gui2 = GUI.fromJson(json);
|
||||
assertEquals(gui2.toJson(), json);
|
||||
assertEquals(gui2.forms, gui2.forms);
|
||||
assertEquals(gui2.params, gui2.params);
|
||||
}
|
||||
|
||||
// Case 1. Old input forms are created in backend, in this case type is always set
|
||||
@Test
|
||||
public void testOldGson_1() throws IOException {
|
||||
|
||||
GUI gui = new GUI();
|
||||
gui.forms.put("textbox_1", new OldInput.OldTextBox("textbox_1", "default_text_1"));
|
||||
gui.forms.put("select_1", new OldInput.OldSelect("select_1", "1", options));
|
||||
gui.forms.put("checkbox_1",
|
||||
new OldInput.OldCheckBox("checkbox_1", checkedItems, options));
|
||||
|
||||
// convert to old json format.
|
||||
String json = gui.toJson();
|
||||
|
||||
// convert to new input forms
|
||||
GUI gui2 = GUI.fromJson(json);
|
||||
assertTrue(3 == gui2.forms.size());
|
||||
assertTrue(gui2.forms.get("textbox_1") instanceof TextBox);
|
||||
assertEquals("default_text_1", gui2.forms.get("textbox_1").getDefaultValue());
|
||||
assertTrue(gui2.forms.get("select_1") instanceof Select);
|
||||
assertEquals(options, ((Select) gui2.forms.get("select_1")).getOptions());
|
||||
assertTrue(gui2.forms.get("checkbox_1") instanceof CheckBox);
|
||||
assertEquals(options, ((CheckBox) gui2.forms.get("checkbox_1")).getOptions());
|
||||
}
|
||||
|
||||
// Case 2. Old input forms are created in frontend, in this case type is only set for checkbox
|
||||
// Actually this is a bug due to method Input#getInputForm
|
||||
@Test
|
||||
public void testOldGson_2() throws IOException {
|
||||
|
||||
GUI gui = new GUI();
|
||||
gui.forms.put("textbox_1", new OldInput("textbox_1", "default_text_1"));
|
||||
gui.forms.put("select_1", new OldInput("select_1", "1", options));
|
||||
gui.forms.put("checkbox_1",
|
||||
new OldInput.OldCheckBox("checkbox_1", checkedItems, options));
|
||||
|
||||
// convert to old json format.
|
||||
String json = gui.toJson();
|
||||
|
||||
// convert to new input forms
|
||||
GUI gui2 = GUI.fromJson(json);
|
||||
assertTrue(3 == gui2.forms.size());
|
||||
assertTrue(gui2.forms.get("textbox_1") instanceof TextBox);
|
||||
assertEquals("default_text_1", gui2.forms.get("textbox_1").getDefaultValue());
|
||||
assertTrue(gui2.forms.get("select_1") instanceof Select);
|
||||
assertEquals(options, ((Select) gui2.forms.get("select_1")).getOptions());
|
||||
assertTrue(gui2.forms.get("checkbox_1") instanceof CheckBox);
|
||||
assertEquals(options, ((CheckBox) gui2.forms.get("checkbox_1")).getOptions());
|
||||
}
|
||||
}
|
||||
|
|
@ -20,16 +20,19 @@ package org.apache.zeppelin.display;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.zeppelin.display.ui.CheckBox;
|
||||
import org.apache.zeppelin.display.ui.OptionInput.ParamOption;
|
||||
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 static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.apache.zeppelin.display.Input.ParamOption;
|
||||
|
||||
public class InputTest {
|
||||
|
||||
@Before
|
||||
|
|
@ -42,7 +45,7 @@ public class InputTest {
|
|||
|
||||
@Test
|
||||
public void testFormExtraction() {
|
||||
// input form
|
||||
// textbox form
|
||||
String script = "${input_form=}";
|
||||
Map<String, Input> forms = Input.extractSimpleQueryForm(script);
|
||||
assertEquals(1, forms.size());
|
||||
|
|
@ -50,50 +53,57 @@ public class InputTest {
|
|||
assertEquals("input_form", form.name);
|
||||
assertNull(form.displayName);
|
||||
assertEquals("", form.defaultValue);
|
||||
assertNull(form.options);
|
||||
assertTrue(form instanceof TextBox);
|
||||
|
||||
// input form with display name & default value
|
||||
// textbox form with display name & default value
|
||||
script = "${input_form(Input Form)=xxx}";
|
||||
forms = Input.extractSimpleQueryForm(script);
|
||||
form = forms.get("input_form");
|
||||
assertEquals("xxx", form.defaultValue);
|
||||
assertTrue(form instanceof TextBox);
|
||||
|
||||
// selection form
|
||||
script = "${select_form(Selection Form)=op1,op1|op2(Option 2)|op3}";
|
||||
form = Input.extractSimpleQueryForm(script).get("select_form");
|
||||
assertEquals("select_form", form.name);
|
||||
assertEquals("op1", form.defaultValue);
|
||||
assertTrue(form instanceof Select);
|
||||
assertArrayEquals(new ParamOption[]{new ParamOption("op1", null),
|
||||
new ParamOption("op2", "Option 2"), new ParamOption("op3", null)}, form.options);
|
||||
new ParamOption("op2", "Option 2"), new ParamOption("op3", null)},
|
||||
((Select) form).getOptions());
|
||||
|
||||
// checkbox form
|
||||
script = "${checkbox:checkbox_form=op1,op1|op2|op3}";
|
||||
form = Input.extractSimpleQueryForm(script).get("checkbox_form");
|
||||
assertEquals("checkbox_form", form.name);
|
||||
assertEquals("checkbox", form.type);
|
||||
assertTrue(form instanceof CheckBox);
|
||||
|
||||
assertArrayEquals(new Object[]{"op1"}, (Object[]) form.defaultValue);
|
||||
assertArrayEquals(new ParamOption[]{new ParamOption("op1", null),
|
||||
new ParamOption("op2", null), new ParamOption("op3", null)}, form.options);
|
||||
new ParamOption("op2", null), new ParamOption("op3", null)},
|
||||
((CheckBox) form).getOptions());
|
||||
|
||||
// checkbox form with multiple default checks
|
||||
script = "${checkbox:checkbox_form(Checkbox Form)=op1|op3,op1(Option 1)|op2|op3}";
|
||||
form = Input.extractSimpleQueryForm(script).get("checkbox_form");
|
||||
assertEquals("checkbox_form", form.name);
|
||||
assertEquals("Checkbox Form", form.displayName);
|
||||
assertEquals("checkbox", form.type);
|
||||
assertTrue(form instanceof CheckBox);
|
||||
assertArrayEquals(new Object[]{"op1", "op3"}, (Object[]) form.defaultValue);
|
||||
assertArrayEquals(new ParamOption[]{new ParamOption("op1", "Option 1"),
|
||||
new ParamOption("op2", null), new ParamOption("op3", null)}, form.options);
|
||||
new ParamOption("op2", null), new ParamOption("op3", null)},
|
||||
((CheckBox) form).getOptions());
|
||||
|
||||
// checkbox form with no default check
|
||||
script = "${checkbox:checkbox_form(Checkbox Form)=,op1(Option 1)|op2(Option 2)|op3(Option 3)}";
|
||||
form = Input.extractSimpleQueryForm(script).get("checkbox_form");
|
||||
assertEquals("checkbox_form", form.name);
|
||||
assertEquals("Checkbox Form", form.displayName);
|
||||
assertEquals("checkbox", form.type);
|
||||
assertTrue(form instanceof CheckBox);
|
||||
assertArrayEquals(new Object[]{}, (Object[]) form.defaultValue);
|
||||
assertArrayEquals(new ParamOption[]{new ParamOption("op1", "Option 1"),
|
||||
new ParamOption("op2", "Option 2"), new ParamOption("op3", "Option 3")}, form.options);
|
||||
new ParamOption("op2", "Option 2"), new ParamOption("op3", "Option 3")},
|
||||
((CheckBox) form).getOptions());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -125,4 +135,5 @@ public class InputTest {
|
|||
assertEquals("INPUT=some_inputSELECTED=s_op2\nCHECKED=c_op1\n" +
|
||||
"NEW_CHECKED=nc_a and nc_c", replaced);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ 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.helium.ApplicationEventListener;
|
||||
import org.apache.zeppelin.helium.HeliumPackage;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
|
|
@ -134,7 +135,9 @@ public class NotebookServer extends WebSocketServlet
|
|||
}
|
||||
}
|
||||
}
|
||||
}).setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
|
||||
}).setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
.registerTypeAdapterFactory(Input.TypeAdapterFactory).create();
|
||||
|
||||
final Map<String, List<NotebookSocket>> noteSocketMap = new HashMap<>();
|
||||
final Queue<NotebookSocket> connectedSockets = new ConcurrentLinkedQueue<>();
|
||||
final Map<String, Queue<NotebookSocket>> userConnectedSockets = new ConcurrentHashMap<>();
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
|
|||
try {
|
||||
createNewNote();
|
||||
|
||||
setTextOfParagraph(1, "%spark println(\"Hello \"+z.input(\"name\", \"world\")) ");
|
||||
setTextOfParagraph(1, "%spark println(\"Hello \"+z.textbox(\"name\", \"world\")) ");
|
||||
|
||||
runParagraph(1);
|
||||
waitForParagraph(1, "FINISHED");
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
p.setConfig(config);
|
||||
String code = "%spark.spark println(z.input(\"my_input\", \"default_name\"))\n" +
|
||||
String code = "%spark.spark println(z.textbox(\"my_input\", \"default_name\"))\n" +
|
||||
"println(z.select(\"my_select\", \"1\"," +
|
||||
"Seq((\"1\", \"select_1\"), (\"2\", \"select_2\"))))\n" +
|
||||
"val items=z.checkbox(\"my_checkbox\", Seq(\"2\"), " +
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ limitations under the License.
|
|||
<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-if="paragraph.settings.forms[formulaire.name].type == 'TextBox'"
|
||||
ng-enter="runParagraphFromButton(getEditorValue())"
|
||||
ng-model="paragraph.settings.params[formulaire.name]"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }"
|
||||
|
|
@ -28,7 +28,7 @@ limitations under the License.
|
|||
</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-if="paragraph.settings.forms[formulaire.name].type == 'Select'"
|
||||
ng-change="runParagraphFromButton(getEditorValue())"
|
||||
ng-model="paragraph.settings.params[formulaire.name]"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }"
|
||||
|
|
@ -38,16 +38,16 @@ limitations under the License.
|
|||
</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">
|
||||
ng-if="paragraph.settings.forms[formulaire.name].type == 'Select'"
|
||||
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.config.runOnSelectionChange == true &&
|
||||
paragraph.settings.forms[formulaire.name].type == 'checkbox'">
|
||||
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"
|
||||
|
|
@ -57,7 +57,7 @@ limitations under the License.
|
|||
</label>
|
||||
</div>
|
||||
<div ng-if="paragraph.config.runOnSelectionChange == false &&
|
||||
paragraph.settings.forms[formulaire.name].type == 'checkbox'">
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ function websocketEvents($rootScope, $websocket, $location, baseUrlSrv) {
|
|||
if (event.data) {
|
||||
payload = angular.fromJson(event.data);
|
||||
}
|
||||
console.log('Receive Json << %o', event.data)
|
||||
console.log('Receive << %o, %o', payload.op, payload);
|
||||
var op = payload.op;
|
||||
var data = payload.data;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import java.util.concurrent.ScheduledFuture;
|
|||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
import org.apache.zeppelin.display.AngularObject;
|
||||
|
|
@ -54,6 +55,9 @@ import com.google.gson.Gson;
|
|||
public class Note implements Serializable, ParagraphJobListener {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Note.class);
|
||||
private static final long serialVersionUID = 7920699076577612429L;
|
||||
private static final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(Input.TypeAdapterFactory)
|
||||
.create();
|
||||
|
||||
// threadpool for delayed persist of note
|
||||
private static final ScheduledThreadPoolExecutor delayedPersistThreadPool =
|
||||
|
|
@ -882,4 +886,19 @@ public class Note implements Serializable, ParagraphJobListener {
|
|||
this.noteEventListener = noteEventListener;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
public static Note fromJson(String json) {
|
||||
Note note = gson.fromJson(json, Note.class);
|
||||
convertOldInput(note);
|
||||
return note;
|
||||
}
|
||||
|
||||
private static void convertOldInput(Note note) {
|
||||
for (Paragraph p : note.paragraphs) {
|
||||
p.settings.convertOldInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ public class AzureNotebookRepo implements NotebookRepo {
|
|||
Gson gson = gsonBuilder.registerTypeAdapter(Date.class, new NotebookImportDeserializer())
|
||||
.create();
|
||||
|
||||
Note note = gson.fromJson(json, Note.class);
|
||||
Note note = Note.fromJson(json);
|
||||
|
||||
for (Paragraph p : note.getParagraphs()) {
|
||||
if (p.getStatus() == Job.Status.PENDING || p.getStatus() == Job.Status.RUNNING) {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ public class S3NotebookRepo implements NotebookRepo {
|
|||
Note note;
|
||||
try (InputStream ins = s3object.getObjectContent()) {
|
||||
String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
|
||||
note = gson.fromJson(json, Note.class);
|
||||
note = Note.fromJson(json);
|
||||
}
|
||||
|
||||
for (Paragraph p : note.getParagraphs()) {
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ public class VFSNotebookRepo implements NotebookRepo {
|
|||
String json = IOUtils.toString(ins, conf.getString(ConfVars.ZEPPELIN_ENCODING));
|
||||
ins.close();
|
||||
|
||||
Note note = gson.fromJson(json, Note.class);
|
||||
Note note = Note.fromJson(json);
|
||||
// note.setReplLoader(replLoader);
|
||||
// note.jobListenerFactory = jobListenerFactory;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue