[ZEPPELIN-3919] Paragraph config default value can be customized

The title of the paragraph of the current notebook is not displayed by default, and the runOnSelectionChange check option is ON by default.
For added flexibility, add the config configuration to the `interpreter-setting.json` file in the interpreter. You can modify the default values with the following four options.

```
"config": {
  "fontSize": 9,
  "colWidth": 12,
  "runOnSelectionChange": false,
  "title": true
}
```

In the `hadoop submarine interpreter`, each paragraph of a notebook represents a complete module of a machine learning algorithm. The name of the algorithm name needs to be filled in through the title of the paragraph.

**Notebook paragraph display title (Optional)**
The notebook paragraph does not display the title by default.
You can have the title of the notebook display the title by `config.title=true`.

**Notebook run on selection change (Optional)**
The dynamic form in the notebook triggers execution when the selection is modified.
You can make the dynamic form in the notebook not trigger execution after selecting the modification by setting `config.runOnSelectionChange=false`.

[Improvement]

* [x] Add paragraph config default configuration in interpreter-setting.json

* https://issues.apache.org/jira/browse/ZEPPELIN-3919

CI pass

![alt text](https://github.com/liuxunorg/images/blob/master/zeppelin/config-setting.gif?raw=true "config-setting")

* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? Yes
This commit is contained in:
liuxunorg 2018-12-21 13:00:02 +08:00
parent 6639025187
commit 5dbb559ad0
9 changed files with 141 additions and 6 deletions

View file

@ -118,6 +118,12 @@ Here is an example of `interpreter-setting.json` on your own interpreter.
"language": "your-syntax-highlight-language",
"editOnDblClick": false,
"completionKey": "TAB"
},
"config": {
"fontSize": 9,
"colWidth": 12,
"runOnSelectionChange": true/false,
"title": true/false
}
},
{
@ -183,6 +189,25 @@ Currently `TAB` is only available option.
}
```
### Notebook paragraph display title (Optional)
The notebook paragraph does not display the title by default.
You can have the title of the notebook display the title by `config.title=true`.
```json
"config": {
"title": true # default: false
}
```
### Notebook run on selection change (Optional)
The dynamic form in the notebook triggers execution when the selection is modified.
You can make the dynamic form in the notebook not trigger execution after selecting the modification by setting `config.runOnSelectionChange=false`.
```json
"config": {
"runOnSelectionChange": false # default: true
}
```
## Install your interpreter binary

View file

@ -419,6 +419,7 @@ public abstract class Interpreter {
private boolean defaultInterpreter;
private Map<String, DefaultInterpreterProperty> properties;
private Map<String, Object> editor;
private Map<String, Object> config;
private String path;
private InterpreterOption option;
private InterpreterRunner runner;
@ -486,6 +487,14 @@ public abstract class Interpreter {
public InterpreterRunner getRunner() {
return runner;
}
public Map<String, Object> getConfig() {
return config;
}
public void setConfig(Map<String, Object> config) {
this.config = config;
}
}
/**

View file

@ -30,6 +30,7 @@ public class InterpreterInfo {
@SerializedName("class") private String className;
private boolean defaultInterpreter = false;
private Map<String, Object> editor;
private Map<String, Object> config;
public InterpreterInfo(String className, String name, boolean defaultInterpreter,
Map<String, Object> editor) {
@ -79,4 +80,12 @@ public class InterpreterInfo {
return sameName && sameClassName && sameIsDefaultInterpreter;
}
public Map<String, Object> getConfig() {
return config;
}
public void setConfig(Map<String, Object> config) {
this.config = config;
}
}

View file

@ -401,6 +401,7 @@ public class InterpreterSettingManager implements InterpreterSettingManagerMBean
InterpreterInfo interpreterInfo =
new InterpreterInfo(registeredInterpreter.getClassName(), registeredInterpreter.getName(),
registeredInterpreter.isDefaultInterpreter(), registeredInterpreter.getEditor());
interpreterInfo.setConfig(registeredInterpreter.getConfig());
group = registeredInterpreter.getGroup();
runner = registeredInterpreter.getRunner();
// use defaultOption if it is not specified in interpreter-setting.json
@ -494,6 +495,22 @@ public class InterpreterSettingManager implements InterpreterSettingManagerMBean
return editor;
}
public Map<String, Object> getConfigSetting(String interpreterGroupId) {
InterpreterSetting interpreterSetting = get(interpreterGroupId);
if (null != interpreterSetting) {
List<InterpreterInfo> interpreterInfos = interpreterSetting.getInterpreterInfos();
for (InterpreterInfo intpInfo : interpreterInfos) {
if (intpInfo.isDefaultInterpreter() || (interpreterInfos.size() == 1)) {
if (intpInfo.getConfig() != null) {
return intpInfo.getConfig();
}
}
}
}
return new HashMap<String, Object>();
}
public List<ManagedInterpreterGroup> getAllInterpreterGroup() {
List<ManagedInterpreterGroup> interpreterGroups = new ArrayList<>();
for (InterpreterSetting interpreterSetting : interpreterSettings.values()) {

View file

@ -365,6 +365,11 @@ public class Note implements JsonSerializable {
*/
public Paragraph insertNewParagraph(int index, AuthenticationInfo authenticationInfo) {
Paragraph paragraph = new Paragraph(this, paragraphJobListener);
if (null != interpreterSettingManager) {
Map<String, Object> config =
interpreterSettingManager.getConfigSetting(defaultInterpreterGroup);
paragraph.setConfig(config);
}
paragraph.setAuthenticationInfo(authenticationInfo);
setParagraphMagic(paragraph, index);
insertParagraph(paragraph, index);

View file

@ -46,7 +46,7 @@ public class InterpreterSettingManagerTest extends AbstractInterpreterTest {
@Test
public void testInitInterpreterSettingManager() throws IOException, RepositoryException {
assertEquals(5, interpreterSettingManager.get().size());
assertEquals(6, interpreterSettingManager.get().size());
InterpreterSetting interpreterSetting = interpreterSettingManager.getByName("test");
assertEquals("test", interpreterSetting.getName());
assertEquals("test", interpreterSetting.getGroup());
@ -76,7 +76,7 @@ public class InterpreterSettingManagerTest extends AbstractInterpreterTest {
// Load it again
InterpreterSettingManager interpreterSettingManager2 = new InterpreterSettingManager(conf,
mock(AngularObjectRegistryListener.class), mock(RemoteInterpreterProcessListener.class), mock(ApplicationEventListener.class));
assertEquals(5, interpreterSettingManager2.get().size());
assertEquals(6, interpreterSettingManager2.get().size());
interpreterSetting = interpreterSettingManager2.getByName("test");
assertEquals("test", interpreterSetting.getName());
assertEquals("test", interpreterSetting.getGroup());
@ -112,7 +112,7 @@ public class InterpreterSettingManagerTest extends AbstractInterpreterTest {
}
interpreterSettingManager.createNewSetting("test3", "test", new ArrayList<Dependency>(), option, properties);
assertEquals(6, interpreterSettingManager.get().size());
assertEquals(7, interpreterSettingManager.get().size());
InterpreterSetting interpreterSetting = interpreterSettingManager.getByName("test3");
assertEquals("test3", interpreterSetting.getName());
assertEquals("test", interpreterSetting.getGroup());
@ -134,7 +134,7 @@ public class InterpreterSettingManagerTest extends AbstractInterpreterTest {
// load it again, it should be saved in interpreter-setting.json. So we can restore it properly
InterpreterSettingManager interpreterSettingManager2 = new InterpreterSettingManager(conf,
mock(AngularObjectRegistryListener.class), mock(RemoteInterpreterProcessListener.class), mock(ApplicationEventListener.class));
assertEquals(6, interpreterSettingManager2.get().size());
assertEquals(7, interpreterSettingManager2.get().size());
interpreterSetting = interpreterSettingManager2.getByName("test3");
assertEquals("test3", interpreterSetting.getName());
assertEquals("test", interpreterSetting.getGroup());
@ -181,12 +181,12 @@ public class InterpreterSettingManagerTest extends AbstractInterpreterTest {
// remove interpreter setting
interpreterSettingManager.remove(interpreterSetting.getId());
assertEquals(5, interpreterSettingManager.get().size());
assertEquals(6, interpreterSettingManager.get().size());
// load it again
InterpreterSettingManager interpreterSettingManager3 = new InterpreterSettingManager(new ZeppelinConfiguration(),
mock(AngularObjectRegistryListener.class), mock(RemoteInterpreterProcessListener.class), mock(ApplicationEventListener.class));
assertEquals(5, interpreterSettingManager3.get().size());
assertEquals(6, interpreterSettingManager3.get().size());
}

View file

@ -52,6 +52,7 @@ import org.sonatype.aether.RepositoryException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
@ -1082,6 +1083,25 @@ public class NotebookTest extends AbstractInterpreterTest implements ParagraphJo
assertEquals(user2Notes.get(0).getId(), note.getId());
}
@Test
public void testInterpreterSettingConfig() throws InterruptedException,
IOException, InterpreterException {
Note note = new Note("testInterpreterSettingConfig", "config_test",
interpreterFactory, interpreterSettingManager, null, null, new ArrayList<>());
// create three paragraphs
Paragraph p1 = note.addNewParagraph(anonymous);
Map<String, Object> config = p1.getConfig();
assertTrue(config.containsKey("fontSize"));
assertTrue(config.containsKey("colWidth"));
assertTrue(config.containsKey("runOnSelectionChange"));
assertTrue(config.containsKey("title"));
assertEquals(config.get("fontSize"), 9.0);
assertEquals(config.get("colWidth"), 12.0);
assertEquals(config.get("runOnSelectionChange"), false);
assertEquals(config.get("title"), true);
}
@Test
public void testAbortParagraphStatusOnInterpreterRestart() throws InterruptedException,
IOException, InterpreterException {

View file

@ -120,6 +120,30 @@
"users": [],
"isUserImpersonate": false
}
},
"2C5EERVGA" : {
"group": "config_test",
"name": "config_test",
"className": "org.apache.zeppelin.interpreter.mock.MockInterpreter1",
"properties": {
},
"config": {
"fontSize": 9,
"colWidth": 12,
"runOnSelectionChange": false,
"title": true
},
"option": {
"remote": true,
"port": -1,
"perNote": "shared",
"perUser": "shared",
"isExistingProcess": false,
"setPermission": false,
"users": [],
"isUserImpersonate": false
}
}
},
"interpreterBindings": {

View file

@ -0,0 +1,26 @@
[
{
"group": "config_test",
"name": "config_test",
"className": "org.apache.zeppelin.interpreter.mock.MockInterpreter1",
"defaultInterpreter": true,
"properties": {
},
"config": {
"fontSize": 9,
"colWidth": 12,
"runOnSelectionChange": false,
"title": true
},
"option": {
"remote": true,
"port": -1,
"perNote": "shared",
"perUser": "shared",
"isExistingProcess": false,
"setPermission": false,
"users": [],
"isUserImpersonate": false
}
}
]