mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Merge branch 'master' of https://github.com/apache/zeppelin into ZEPPELIN-1935
This commit is contained in:
commit
dfabe3ac3d
88 changed files with 6814 additions and 6517 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -45,6 +45,7 @@ zeppelin-web/src/fonts/patua-one*
|
|||
zeppelin-web/src/fonts/google-fonts.css
|
||||
zeppelin-web/.sass-cache
|
||||
zeppelin-web/npm-debug.log
|
||||
zeppelin-web/yarn-error.log
|
||||
zeppelin-web/bower_components
|
||||
zeppelin-web/yarn.lock
|
||||
**nbproject/
|
||||
|
|
|
|||
10
.travis.yml
10
.travis.yml
|
|
@ -42,19 +42,19 @@ matrix:
|
|||
|
||||
# Test all modules with spark 2.0.2 and scala 2.11
|
||||
- jdk: "oraclejdk7"
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pspark-2.0 -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Pspark-2.0 -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
|
||||
# Test all modules with spark 2.1.0 and scala 2.11
|
||||
- jdk: "oraclejdk7"
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.0 -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pspark-2.0 -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
|
||||
# Test all modules with scala 2.10
|
||||
- jdk: "oraclejdk7"
|
||||
env: SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Pbeam -Pexamples -Pscala-2.10" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
env: SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Pbeam -Phelium-dev -Pexamples -Pscala-2.10" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
|
||||
# Test all modules with scala 2.11
|
||||
- jdk: "oraclejdk7"
|
||||
env: SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
env: SCALA_VER="2.11" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.6 -Ppyspark -Psparkr -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
|
||||
|
||||
# Test spark module for 1.5.2
|
||||
- jdk: "oraclejdk7"
|
||||
|
|
@ -66,7 +66,7 @@ matrix:
|
|||
|
||||
# Test selenium with spark module for 1.6.3
|
||||
- jdk: "oraclejdk7"
|
||||
env: TEST_SELENIUM="true" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop-2.6 -Ppyspark -Pexamples" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
|
||||
env: TEST_SELENIUM="true" SCALA_VER="2.10" SPARK_VER="1.6.3" HADOOP_VER="2.6" PROFILE="-Pspark-1.6 -Phadoop-2.6 -Ppyspark -Phelium-dev -Pexamples" BUILD_FLAG="package -DskipTests -DskipRat" TEST_FLAG="verify -DskipRat" TEST_PROJECTS="-pl zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
|
||||
|
||||
# Test python/pyspark with python 2
|
||||
- jdk: "oraclejdk7"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ REM set ZEPPELIN_NOTEBOOK_HOMESCREEN REM Id of notebook to be displayed in home
|
|||
REM set ZEPPELIN_NOTEBOOK_HOMESCREEN_HIDE REM hide homescreen notebook from list when this value set to "true". default "false"
|
||||
REM set ZEPPELIN_NOTEBOOK_S3_BUCKET REM Bucket where notebook saved
|
||||
REM set ZEPPELIN_NOTEBOOK_S3_USER REM User in bucket where notebook saved. For example bucket/user/notebook/2A94M5J1Z/note.json
|
||||
REM set ZEPPELIN_NOTEBOOK_S3_ENDPOINT REM Endpoint of the bucket
|
||||
REM set ZEPPELIN_NOTEBOOK_S3_KMS_KEY_ID REM AWS KMS key ID
|
||||
REM set ZEPPELIN_NOTEBOOK_S3_KMS_KEY_REGION REM AWS KMS key region
|
||||
REM set ZEPPELIN_IDENT_STRING REM A string representing this instance of zeppelin. $USER by default.
|
||||
REM set ZEPPELIN_NICENESS REM The scheduling priority for daemons. Defaults to 0.
|
||||
REM set ZEPPELIN_INTERPRETER_LOCALREPO REM Local repository for interpreter's additional dependency loading
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
# export ZEPPELIN_NOTEBOOK_S3_BUCKET # Bucket where notebook saved
|
||||
# export ZEPPELIN_NOTEBOOK_S3_ENDPOINT # Endpoint of the bucket
|
||||
# export ZEPPELIN_NOTEBOOK_S3_USER # User in bucket where notebook saved. For example bucket/user/notebook/2A94M5J1Z/note.json
|
||||
# export ZEPPELIN_NOTEBOOK_S3_KMS_KEY_ID # AWS KMS key ID
|
||||
# export ZEPPELIN_NOTEBOOK_S3_KMS_KEY_REGION # AWS KMS key region
|
||||
# export ZEPPELIN_IDENT_STRING # A string representing this instance of zeppelin. $USER by default.
|
||||
# export ZEPPELIN_NICENESS # The scheduling priority for daemons. Defaults to 0.
|
||||
# export ZEPPELIN_INTERPRETER_LOCALREPO # Local repository for interpreter's additional dependency loading
|
||||
|
|
|
|||
|
|
@ -108,6 +108,16 @@
|
|||
</property>
|
||||
-->
|
||||
|
||||
<!-- provide region of your KMS key -->
|
||||
<!-- See http://docs.aws.amazon.com/general/latest/gr/rande.html#kms_region for region codes names -->
|
||||
<!--
|
||||
<property>
|
||||
<name>zeppelin.notebook.s3.kmsKeyRegion</name>
|
||||
<value>us-east-1</value>
|
||||
<description>AWS KMS key region in your AWS account</description>
|
||||
</property>
|
||||
-->
|
||||
|
||||
<!-- Use a custom encryption materials provider to encrypt data -->
|
||||
<!-- No configuration is given to the provider, so you must use system properties or another means to configure -->
|
||||
<!-- See https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/EncryptionMaterialsProvider.html -->
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ You can check example applications under [./zeppelin-examples](https://github.co
|
|||
|
||||
In the development mode, you can run your Application in your IDE as a normal java application and see the result inside of Zeppelin notebook.
|
||||
|
||||
`org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer` can run Zeppelin Application in development mode.
|
||||
`org.apache.zeppelin.helium.ZeppelinApplicationDevServer` can run Zeppelin Application in development mode.
|
||||
|
||||
```java
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ public static void main(String[] args) throws Exception {
|
|||
|
||||
// run application in devlopment mode with given resource
|
||||
// in this case, Clock.class.getName() will be the application class name
|
||||
ZeppelinApplicationDevServer devServer = new ZeppelinApplicationDevServer(
|
||||
org.apache.zeppelin.helium.ZeppelinApplicationDevServer devServer = new org.apache.zeppelin.helium.ZeppelinApplicationDevServer(
|
||||
Clock.class.getName(), pool.getAll());
|
||||
|
||||
// start development mode
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -130,6 +130,23 @@ Or using the following setting in **zeppelin-site.xml**:
|
|||
</property>
|
||||
```
|
||||
|
||||
In order to set custom KMS key region, set the following environment variable in the file **zeppelin-env.sh**:
|
||||
|
||||
```
|
||||
export ZEPPELIN_NOTEBOOK_S3_KMS_KEY_REGION = kms-key-region
|
||||
```
|
||||
|
||||
Or using the following setting in **zeppelin-site.xml**:
|
||||
|
||||
```
|
||||
<property>
|
||||
<name>zeppelin.notebook.s3.kmsKeyRegion</name>
|
||||
<value>target-region</value>
|
||||
<description>AWS KMS key region in your AWS account</description>
|
||||
</property>
|
||||
```
|
||||
Format of `target-region` is described in more details [here](http://docs.aws.amazon.com/general/latest/gr/rande.html#kms_region) in second `Region` column (e.g. `us-east-1`).
|
||||
|
||||
#### Custom Encryption Materials Provider class
|
||||
|
||||
You may use a custom [``EncryptionMaterialsProvider``](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/EncryptionMaterialsProvider.html) class as long as it is available in the classpath and able to initialize itself from system properties or another mechanism. To use this, set the following environment variable in the file **zeppelin-env.sh**:
|
||||
|
|
@ -238,4 +255,4 @@ export ZEPPELINHUB_API_TOKEN = ZeppelinHub token
|
|||
export ZEPPELINHUB_API_ADDRESS = address of ZeppelinHub service (e.g. https://www.zeppelinhub.com)
|
||||
```
|
||||
|
||||
You can get more information on generating `token` and using authentication on the corresponding [help page](http://help.zeppelinhub.com/zeppelin_integration/#add-a-new-zeppelin-instance-and-generate-a-token).
|
||||
You can get more information on generating `token` and using authentication on the corresponding [help page](http://help.zeppelinhub.com/zeppelin_integration/#add-a-new-zeppelin-instance-and-generate-a-token).
|
||||
|
|
|
|||
89
helium-dev/pom.xml
Normal file
89
helium-dev/pom.xml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>zeppelin</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>helium-dev</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
<name>Zeppelin: Helium development interpreter</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>zeppelin-interpreter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/../../interpreter/helium-dev</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-artifact</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/../../interpreter/helium-dev</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<includeScope>runtime</includeScope>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>${project.artifactId}</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>${project.packaging}</type>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -14,7 +14,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.zeppelin.interpreter.dev;
|
||||
|
||||
package org.apache.zeppelin.helium;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
|
@ -48,7 +49,7 @@ public class DevInterpreter extends Interpreter {
|
|||
}
|
||||
|
||||
/**
|
||||
* event handler for ZeppelinApplicationDevServer
|
||||
* event handler for org.apache.zeppelin.helium.ZeppelinApplicationDevServer
|
||||
*/
|
||||
public static interface InterpreterEvent {
|
||||
public InterpreterResult interpret(String st, InterpreterContext context);
|
||||
|
|
@ -14,23 +14,20 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.zeppelin.interpreter.dev;
|
||||
|
||||
package org.apache.zeppelin.helium;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.apache.zeppelin.helium.*;
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient;
|
||||
import org.apache.zeppelin.resource.ResourceSet;
|
||||
import org.apache.zeppelin.resource.WellKnownResourceName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -47,7 +44,7 @@ public class ZeppelinApplicationDevServer extends ZeppelinDevServer {
|
|||
|
||||
public ZeppelinApplicationDevServer(final String className, ResourceSet resourceSet) throws
|
||||
Exception {
|
||||
this(ZeppelinDevServer.DEFAULT_TEST_INTERPRETER_PORT, className, resourceSet);
|
||||
this(Constants.ZEPPELIN_INTERPRETER_DEFAUlT_PORT, className, resourceSet);
|
||||
}
|
||||
|
||||
public ZeppelinApplicationDevServer(int port, String className, ResourceSet resourceSet) throws
|
||||
|
|
@ -14,16 +14,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.zeppelin.interpreter.dev;
|
||||
|
||||
package org.apache.zeppelin.helium;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.thrift.TException;
|
||||
import org.apache.zeppelin.helium.DevInterpreter.InterpreterEvent;
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.dev.DevInterpreter.InterpreterEvent;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterServer;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -34,11 +34,10 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public class ZeppelinDevServer extends
|
||||
RemoteInterpreterServer implements InterpreterEvent, InterpreterOutputChangeListener {
|
||||
final Logger logger = LoggerFactory.getLogger(ZeppelinDevServer.class);
|
||||
public static final int DEFAULT_TEST_INTERPRETER_PORT = 29914;
|
||||
private static final Logger logger = LoggerFactory.getLogger(ZeppelinDevServer.class);
|
||||
|
||||
DevInterpreter interpreter = null;
|
||||
InterpreterOutput out;
|
||||
private DevInterpreter interpreter = null;
|
||||
private InterpreterOutput out;
|
||||
public ZeppelinDevServer(int port) throws TException {
|
||||
super(port);
|
||||
}
|
||||
|
|
@ -47,21 +46,21 @@ public class ZeppelinDevServer extends
|
|||
protected Interpreter getInterpreter(String sessionKey, String className) throws TException {
|
||||
synchronized (this) {
|
||||
InterpreterGroup interpreterGroup = getInterpreterGroup();
|
||||
if (interpreterGroup == null) {
|
||||
if (interpreterGroup == null || interpreterGroup.isEmpty()) {
|
||||
createInterpreter(
|
||||
"dev",
|
||||
sessionKey,
|
||||
DevInterpreter.class.getName(),
|
||||
new HashMap<String, String>(),
|
||||
"anonymous");
|
||||
|
||||
Interpreter intp = super.getInterpreter(sessionKey, className);
|
||||
interpreter = (DevInterpreter) (
|
||||
((LazyOpenInterpreter) intp).getInnerInterpreter());
|
||||
interpreter.setInterpreterEvent(this);
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
Interpreter intp = super.getInterpreter(sessionKey, className);
|
||||
interpreter = (DevInterpreter) (
|
||||
((LazyOpenInterpreter) intp).getInnerInterpreter());
|
||||
interpreter.setInterpreterEvent(this);
|
||||
return super.getInterpreter(sessionKey, className);
|
||||
}
|
||||
|
||||
19
helium-dev/src/main/resources/interpreter-setting.json
Normal file
19
helium-dev/src/main/resources/interpreter-setting.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[
|
||||
{
|
||||
"group": "dev",
|
||||
"name": "dev",
|
||||
"className": "org.apache.zeppelin.helium.DevInterpreter",
|
||||
"properties": {
|
||||
"port": {
|
||||
"envName": "PORT",
|
||||
"propertyName": "port",
|
||||
"defaultValue": "jdbc:postgresql://localhost:5432/",
|
||||
"description": "The URL for JDBC."
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"language": "helium",
|
||||
"editOnDblClick": false
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -19,7 +19,6 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
|
|||
import static org.apache.commons.lang.StringUtils.isNotEmpty;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.IOException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
|
@ -34,10 +33,7 @@ import org.apache.hadoop.conf.Configuration;
|
|||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.security.alias.CredentialProvider;
|
||||
import org.apache.hadoop.security.alias.CredentialProviderFactory;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.jdbc.security.JDBCSecurityImpl;
|
||||
|
|
@ -481,6 +477,57 @@ public class JDBCInterpreter extends Interpreter {
|
|||
return updatedCount < 0 && columnCount <= 0 ? true : false;
|
||||
}
|
||||
|
||||
/*
|
||||
inspired from https://github.com/postgres/pgadmin3/blob/794527d97e2e3b01399954f3b79c8e2585b908dd/
|
||||
pgadmin/dlg/dlgProperty.cpp#L999-L1045
|
||||
*/
|
||||
protected ArrayList<String> splitSqlQueries(String sql) {
|
||||
ArrayList<String> queries = new ArrayList<>();
|
||||
StringBuilder query = new StringBuilder();
|
||||
Character character;
|
||||
|
||||
Boolean antiSlash = false;
|
||||
Boolean quoteString = false;
|
||||
Boolean doubleQuoteString = false;
|
||||
|
||||
for (int item = 0; item < sql.length(); item++) {
|
||||
character = sql.charAt(item);
|
||||
|
||||
if (character.equals('\\')) {
|
||||
antiSlash = true;
|
||||
}
|
||||
if (character.equals('\'')) {
|
||||
if (antiSlash) {
|
||||
antiSlash = false;
|
||||
} else if (quoteString) {
|
||||
quoteString = false;
|
||||
} else if (!doubleQuoteString) {
|
||||
quoteString = true;
|
||||
}
|
||||
}
|
||||
if (character.equals('"')) {
|
||||
if (antiSlash) {
|
||||
antiSlash = false;
|
||||
} else if (doubleQuoteString) {
|
||||
doubleQuoteString = false;
|
||||
} else if (!quoteString) {
|
||||
doubleQuoteString = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (character.equals(';') && !antiSlash && !quoteString && !doubleQuoteString) {
|
||||
queries.add(query.toString());
|
||||
query = new StringBuilder();
|
||||
} else if (item == sql.length() - 1) {
|
||||
query.append(character);
|
||||
queries.add(query.toString());
|
||||
} else {
|
||||
query.append(character);
|
||||
}
|
||||
}
|
||||
return queries;
|
||||
}
|
||||
|
||||
private InterpreterResult executeSql(String propertyKey, String sql,
|
||||
InterpreterContext interpreterContext) {
|
||||
Connection connection;
|
||||
|
|
@ -489,60 +536,68 @@ public class JDBCInterpreter extends Interpreter {
|
|||
String paragraphId = interpreterContext.getParagraphId();
|
||||
String user = interpreterContext.getAuthenticationInfo().getUser();
|
||||
|
||||
try {
|
||||
String results = null;
|
||||
connection = getConnection(propertyKey, interpreterContext);
|
||||
InterpreterResult interpreterResult = new InterpreterResult(InterpreterResult.Code.SUCCESS);
|
||||
|
||||
try {
|
||||
connection = getConnection(propertyKey, interpreterContext);
|
||||
if (connection == null) {
|
||||
return new InterpreterResult(Code.ERROR, "Prefix not found.");
|
||||
}
|
||||
|
||||
statement = connection.createStatement();
|
||||
if (statement == null) {
|
||||
return new InterpreterResult(Code.ERROR, "Prefix not found.");
|
||||
}
|
||||
ArrayList<String> multipleSqlArray = splitSqlQueries(sql);
|
||||
for (int i = 0; i < multipleSqlArray.size(); i++) {
|
||||
String sqlToExecute = multipleSqlArray.get(i);
|
||||
statement = connection.createStatement();
|
||||
if (statement == null) {
|
||||
return new InterpreterResult(Code.ERROR, "Prefix not found.");
|
||||
}
|
||||
|
||||
try {
|
||||
getJDBCConfiguration(user).saveStatement(paragraphId, statement);
|
||||
try {
|
||||
getJDBCConfiguration(user).saveStatement(paragraphId, statement);
|
||||
|
||||
boolean isResultSetAvailable = statement.execute(sql);
|
||||
if (isResultSetAvailable) {
|
||||
resultSet = statement.getResultSet();
|
||||
boolean isResultSetAvailable = statement.execute(sqlToExecute);
|
||||
if (isResultSetAvailable) {
|
||||
resultSet = statement.getResultSet();
|
||||
|
||||
// Regards that the command is DDL.
|
||||
if (isDDLCommand(statement.getUpdateCount(), resultSet.getMetaData().getColumnCount())) {
|
||||
results = "Query executed successfully.";
|
||||
// Regards that the command is DDL.
|
||||
if (isDDLCommand(statement.getUpdateCount(),
|
||||
resultSet.getMetaData().getColumnCount())) {
|
||||
interpreterResult.add(InterpreterResult.Type.TEXT,
|
||||
"Query executed successfully.");
|
||||
} else {
|
||||
interpreterResult.add(
|
||||
getResults(resultSet, !containsIgnoreCase(sqlToExecute, EXPLAIN_PREDICATE)));
|
||||
}
|
||||
} else {
|
||||
results = getResults(resultSet, !containsIgnoreCase(sql, EXPLAIN_PREDICATE));
|
||||
// Response contains either an update count or there are no results.
|
||||
int updateCount = statement.getUpdateCount();
|
||||
interpreterResult.add(InterpreterResult.Type.TEXT,
|
||||
"Query executed successfully. Affected rows : " +
|
||||
updateCount);
|
||||
}
|
||||
} finally {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
} else {
|
||||
// Response contains either an update count or there are no results.
|
||||
int updateCount = statement.getUpdateCount();
|
||||
results = "Query executed successfully. Affected rows : " + updateCount;
|
||||
}
|
||||
//In case user ran an insert/update/upsert statement
|
||||
if (connection.getAutoCommit() != true) connection.commit();
|
||||
|
||||
} finally {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
getJDBCConfiguration(user).removeStatement(paragraphId);
|
||||
}
|
||||
return new InterpreterResult(Code.SUCCESS, results);
|
||||
|
||||
//In case user ran an insert/update/upsert statement
|
||||
if (connection != null) {
|
||||
try {
|
||||
if (!connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
}
|
||||
connection.close();
|
||||
} catch (SQLException e) { /*ignored*/ }
|
||||
}
|
||||
getJDBCConfiguration(user).removeStatement(paragraphId);
|
||||
} catch (Exception e) {
|
||||
logger.error("Cannot run " + sql, e);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
|
@ -555,9 +610,10 @@ public class JDBCInterpreter extends Interpreter {
|
|||
} catch (SQLException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
return new InterpreterResult(Code.ERROR, errorMsg);
|
||||
interpreterResult.add(errorMsg);
|
||||
return new InterpreterResult(Code.ERROR, interpreterResult.message());
|
||||
}
|
||||
return interpreterResult;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@
|
|||
package org.apache.zeppelin.jdbc;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.zeppelin.interpreter.Interpreter.logger;
|
||||
import static org.apache.zeppelin.interpreter.Interpreter.register;
|
||||
import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_KEY;
|
||||
import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_DRIVER;
|
||||
import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_PASSWORD;
|
||||
import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_USER;
|
||||
|
|
@ -29,19 +26,17 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.jdbc.JDBCInterpreter;
|
||||
import org.apache.zeppelin.scheduler.FIFOScheduler;
|
||||
import org.apache.zeppelin.scheduler.ParallelScheduler;
|
||||
import org.apache.zeppelin.scheduler.Scheduler;
|
||||
import org.apache.zeppelin.user.AuthenticationInfo;
|
||||
import org.apache.zeppelin.user.Credentials;
|
||||
import org.apache.zeppelin.user.UserCredentials;
|
||||
import org.apache.zeppelin.user.UsernamePassword;
|
||||
import org.junit.Before;
|
||||
|
|
@ -171,6 +166,49 @@ public class JDBCInterpreterTest extends BasicJDBCTestCaseAdapter {
|
|||
assertEquals("ID\tNAME\na\ta_name\nb\tb_name\n", interpreterResult.message().get(0).getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitSqlQuery() throws SQLException, IOException {
|
||||
String sqlQuery = "insert into test_table(id, name) values ('a', ';\"');" +
|
||||
"select * from test_table;" +
|
||||
"select * from test_table WHERE ID = \";'\";" +
|
||||
"select * from test_table WHERE ID = ';'";
|
||||
|
||||
Properties properties = new Properties();
|
||||
JDBCInterpreter t = new JDBCInterpreter(properties);
|
||||
t.open();
|
||||
ArrayList<String> multipleSqlArray = t.splitSqlQueries(sqlQuery);
|
||||
assertEquals(4, multipleSqlArray.size());
|
||||
assertEquals("insert into test_table(id, name) values ('a', ';\"')", multipleSqlArray.get(0));
|
||||
assertEquals("select * from test_table", multipleSqlArray.get(1));
|
||||
assertEquals("select * from test_table WHERE ID = \";'\"", multipleSqlArray.get(2));
|
||||
assertEquals("select * from test_table WHERE ID = ';'", multipleSqlArray.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectMultipleQuries() throws SQLException, IOException {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("common.max_count", "1000");
|
||||
properties.setProperty("common.max_retry", "3");
|
||||
properties.setProperty("default.driver", "org.h2.Driver");
|
||||
properties.setProperty("default.url", getJdbcConnection());
|
||||
properties.setProperty("default.user", "");
|
||||
properties.setProperty("default.password", "");
|
||||
JDBCInterpreter t = new JDBCInterpreter(properties);
|
||||
t.open();
|
||||
|
||||
String sqlQuery = "select * from test_table;" +
|
||||
"select * from test_table WHERE ID = ';';";
|
||||
InterpreterResult interpreterResult = t.interpret(sqlQuery, interpreterContext);
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code());
|
||||
assertEquals(2, interpreterResult.message().size());
|
||||
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType());
|
||||
assertEquals("ID\tNAME\na\ta_name\nb\tb_name\nc\tnull\n", interpreterResult.message().get(0).getData());
|
||||
|
||||
assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(1).getType());
|
||||
assertEquals("ID\tNAME\n", interpreterResult.message().get(1).getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectQueryWithNull() throws SQLException, IOException {
|
||||
Properties properties = new Properties();
|
||||
|
|
|
|||
7
pom.xml
7
pom.xml
|
|
@ -726,6 +726,13 @@
|
|||
</modules>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>helium-dev</id>
|
||||
<modules>
|
||||
<module>helium-dev</module>
|
||||
</modules>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>build-distr</id>
|
||||
<activation>
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ public class PythonInterpreter extends Interpreter {
|
|||
// Add matplotlib display hook
|
||||
InterpreterGroup intpGroup = getInterpreterGroup();
|
||||
if (intpGroup != null && intpGroup.getInterpreterHookRegistry() != null) {
|
||||
registerHook(HookType.POST_EXEC_DEV, "z._displayhook()");
|
||||
registerHook(HookType.POST_EXEC_DEV, "\nz._displayhook()");
|
||||
}
|
||||
|
||||
|
||||
// Add zeppelin-bundled libs to PYTHONPATH
|
||||
setPythonPath("../interpreter/lib/python:$PYTHONPATH");
|
||||
LOG.info("Starting Python interpreter ---->");
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import org.apache.zeppelin.interpreter.ClassloaderInterpreter;
|
|||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.InterpreterGroup;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
|
@ -62,6 +63,7 @@ import org.slf4j.LoggerFactory;
|
|||
public class PythonInterpreterTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PythonProcess.class);
|
||||
|
||||
PythonInterpreter zeppelinPythonInterpreter = null;
|
||||
PythonInterpreter pythonInterpreter = null;
|
||||
PythonProcess mockPythonProcess;
|
||||
String cmdHistory;
|
||||
|
|
@ -88,6 +90,7 @@ public class PythonInterpreterTest {
|
|||
|
||||
// python interpreter
|
||||
pythonInterpreter = spy(new PythonInterpreter(getPythonTestProperties()));
|
||||
zeppelinPythonInterpreter = new PythonInterpreter(getPythonTestProperties());
|
||||
|
||||
// create interpreter group
|
||||
InterpreterGroup group = new InterpreterGroup();
|
||||
|
|
@ -99,6 +102,12 @@ public class PythonInterpreterTest {
|
|||
when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn("ImportError");
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws IOException {
|
||||
pythonInterpreter.close();
|
||||
zeppelinPythonInterpreter.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenInterpreter() {
|
||||
pythonInterpreter.open();
|
||||
|
|
@ -172,6 +181,18 @@ public class PythonInterpreterTest {
|
|||
assertEquals("%text print a", result.message().get(0).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterpretInvalidSyntax() {
|
||||
zeppelinPythonInterpreter.open();
|
||||
InterpreterResult result = zeppelinPythonInterpreter.interpret("for x in range(0,3): print (\"hi\")\n\nz._displayhook()", null);
|
||||
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
|
||||
assertTrue(result.message().get(0).toString().contains("hi\nhi\nhi"));
|
||||
|
||||
result = zeppelinPythonInterpreter.interpret("for x in range(0,3): print (\"hi\")\nz._displayhook()", null);
|
||||
assertEquals(InterpreterResult.Code.ERROR, result.code());
|
||||
assertTrue(result.message().get(0).toString().contains("SyntaxError: invalid syntax"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given port is open on 'localhost'
|
||||
* @param port
|
||||
|
|
|
|||
|
|
@ -230,5 +230,4 @@ public class SparkRInterpreter extends Interpreter {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
boolean rScriptInitialized = false;
|
||||
Integer rScriptInitializeNotifier = new Integer(0);
|
||||
|
||||
|
||||
/**
|
||||
* Request to R repl
|
||||
*/
|
||||
|
|
@ -103,8 +102,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
boolean rResponseError = false;
|
||||
Integer rResponseNotifier = new Integer(0);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create ZeppelinR instance
|
||||
* @param rCmdPath R repl commandline path
|
||||
|
|
@ -216,7 +213,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send request to r repl and return response
|
||||
* @return responseValue
|
||||
|
|
@ -257,7 +253,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait until src/main/resources/R/zeppelin_sparkr.R is initialized
|
||||
* and call onScriptInitialized()
|
||||
|
|
@ -286,14 +281,11 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
if (rScriptInitialized == false) {
|
||||
throw new InterpreterException("sparkr is not responding " + errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* invoked by src/main/resources/R/zeppelin_sparkr.R
|
||||
* @return
|
||||
|
|
@ -337,7 +329,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create R script in tmp dir
|
||||
*/
|
||||
|
|
@ -381,7 +372,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
return zeppelinR.get(hashcode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pass InterpreterOutput to capture the repl output
|
||||
* @param out
|
||||
|
|
@ -390,8 +380,6 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
outputStream.setInterpreterOutput(out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onProcessComplete(int i) {
|
||||
logger.info("process complete {}", i);
|
||||
|
|
@ -403,6 +391,4 @@ public class ZeppelinR implements ExecuteResultHandler {
|
|||
logger.error(e.getMessage(), e);
|
||||
rScriptRunning = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ object ZeppelinRDisplay {
|
|||
}
|
||||
|
||||
private def htmlDisplay(body: Element, imageWidth: String): RDisplay = {
|
||||
|
||||
var div = new String()
|
||||
|
||||
for (element <- body.children) {
|
||||
|
|
@ -101,7 +100,6 @@ object ZeppelinRDisplay {
|
|||
val r = (pattern findFirstIn eHtml).getOrElse("")
|
||||
|
||||
div = div + eOuterHtml.replace(r, "")
|
||||
|
||||
}
|
||||
|
||||
val content = div
|
||||
|
|
@ -115,7 +113,5 @@ object ZeppelinRDisplay {
|
|||
}
|
||||
|
||||
RDisplay(body.html, HTML, SUCCESS)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,16 @@
|
|||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>zeppelin-interpreter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.zeppelin</groupId>
|
||||
<artifactId>helium-dev</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package org.apache.zeppelin.example.app.clock;
|
|||
import org.apache.zeppelin.helium.Application;
|
||||
import org.apache.zeppelin.helium.ApplicationContext;
|
||||
import org.apache.zeppelin.helium.ApplicationException;
|
||||
import org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer;
|
||||
import org.apache.zeppelin.helium.ZeppelinApplicationDevServer;
|
||||
import org.apache.zeppelin.resource.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@
|
|||
<artifactId>zeppelin-interpreter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>helium-dev</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.zeppelin.helium.Application;
|
||||
import org.apache.zeppelin.helium.ApplicationContext;
|
||||
import org.apache.zeppelin.helium.ApplicationException;
|
||||
import org.apache.zeppelin.helium.ZeppelinApplicationDevServer;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer;
|
||||
import org.apache.zeppelin.resource.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
|||
|
|
@ -28,4 +28,6 @@ public class Constants {
|
|||
|
||||
public static final String EXISTING_PROCESS = "existing_process";
|
||||
|
||||
public static final int ZEPPELIN_INTERPRETER_DEFAUlT_PORT = 29914;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,12 @@
|
|||
|
||||
package org.apache.zeppelin.interpreter.remote;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.rmi.server.RemoteServer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.thrift.TException;
|
||||
import org.apache.thrift.server.TThreadPoolServer;
|
||||
|
|
@ -39,7 +35,6 @@ import org.apache.zeppelin.interpreter.*;
|
|||
import org.apache.zeppelin.interpreter.InterpreterHookRegistry.HookType;
|
||||
import org.apache.zeppelin.interpreter.InterpreterHookListener;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.dev.ZeppelinDevServer;
|
||||
import org.apache.zeppelin.interpreter.thrift.*;
|
||||
import org.apache.zeppelin.resource.*;
|
||||
import org.apache.zeppelin.scheduler.Job;
|
||||
|
|
@ -144,7 +139,7 @@ public class RemoteInterpreterServer
|
|||
public static void main(String[] args)
|
||||
throws TTransportException, InterruptedException {
|
||||
|
||||
int port = ZeppelinDevServer.DEFAULT_TEST_INTERPRETER_PORT;
|
||||
int port = Constants.ZEPPELIN_INTERPRETER_DEFAUlT_PORT;
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0]);
|
||||
}
|
||||
|
|
@ -442,7 +437,7 @@ public class RemoteInterpreterServer
|
|||
public void onPreExecute(String script) {
|
||||
String cmdDev = interpreter.getHook(noteId, HookType.PRE_EXEC_DEV);
|
||||
String cmdUser = interpreter.getHook(noteId, HookType.PRE_EXEC);
|
||||
|
||||
|
||||
// User defined hook should be executed before dev hook
|
||||
List<String> cmds = Arrays.asList(cmdDev, cmdUser);
|
||||
for (String cmd : cmds) {
|
||||
|
|
@ -450,15 +445,15 @@ public class RemoteInterpreterServer
|
|||
script = cmd + '\n' + script;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InterpretJob.this.script = script;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPostExecute(String script) {
|
||||
String cmdDev = interpreter.getHook(noteId, HookType.POST_EXEC_DEV);
|
||||
String cmdUser = interpreter.getHook(noteId, HookType.POST_EXEC);
|
||||
|
||||
|
||||
// User defined hook should be executed after dev hook
|
||||
List<String> cmds = Arrays.asList(cmdUser, cmdDev);
|
||||
for (String cmd : cmds) {
|
||||
|
|
@ -466,7 +461,7 @@ public class RemoteInterpreterServer
|
|||
script += '\n' + cmd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
InterpretJob.this.script = script;
|
||||
}
|
||||
};
|
||||
|
|
@ -478,7 +473,7 @@ public class RemoteInterpreterServer
|
|||
protected Object jobRun() throws Throwable {
|
||||
try {
|
||||
InterpreterContext.set(context);
|
||||
|
||||
|
||||
// Open the interpreter instance prior to calling interpret().
|
||||
// This is necessary because the earliest we can register a hook
|
||||
// is from within the open() method.
|
||||
|
|
@ -486,7 +481,7 @@ public class RemoteInterpreterServer
|
|||
if (!lazy.isOpen()) {
|
||||
lazy.open();
|
||||
}
|
||||
|
||||
|
||||
// Add hooks to script from registry.
|
||||
// Global scope first, followed by notebook scope
|
||||
processInterpreterHooks(null);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.*;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.vfs2.FileSystemException;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
|
|
@ -85,8 +86,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
|
|
@ -263,6 +262,9 @@ public class NotebookServer extends WebSocketServlet
|
|||
case RUN_PARAGRAPH:
|
||||
runParagraph(conn, userAndRoles, notebook, messagereceived);
|
||||
break;
|
||||
case RUN_ALL_PARAGRAPHS:
|
||||
runAllParagraphs(conn, userAndRoles, notebook, messagereceived);
|
||||
break;
|
||||
case CANCEL_PARAGRAPH:
|
||||
cancelParagraph(conn, userAndRoles, notebook, messagereceived);
|
||||
break;
|
||||
|
|
@ -1534,8 +1536,46 @@ public class NotebookServer extends WebSocketServlet
|
|||
p.abort();
|
||||
}
|
||||
|
||||
private void runParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
|
||||
private void runAllParagraphs(NotebookSocket conn, HashSet<String> userAndRoles,
|
||||
Notebook notebook,
|
||||
Message fromMessage) throws IOException {
|
||||
final String noteId = (String) fromMessage.get("noteId");
|
||||
if (StringUtils.isBlank(noteId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Note note = notebook.getNote(noteId);
|
||||
NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
|
||||
if (!notebookAuthorization.isWriter(noteId, userAndRoles)) {
|
||||
permissionError(conn, "run all paragraphs", fromMessage.principal, userAndRoles,
|
||||
notebookAuthorization.getOwners(noteId));
|
||||
return;
|
||||
}
|
||||
|
||||
List<Map<String, Object>> paragraphs =
|
||||
gson.fromJson(String.valueOf(fromMessage.data.get("paragraphs")),
|
||||
new TypeToken<List<Map<String, Object>>>() {}.getType());
|
||||
|
||||
for (Map<String, Object> raw : paragraphs) {
|
||||
String paragraphId = (String) raw.get("id");
|
||||
if (paragraphId == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String text = (String) raw.get("paragraph");
|
||||
String title = (String) raw.get("title");
|
||||
Map<String, Object> params = (Map<String, Object>) raw.get("params");
|
||||
Map<String, Object> config = (Map<String, Object>) raw.get("config");
|
||||
|
||||
Paragraph p = setParagraphUsingMessage(note, fromMessage,
|
||||
paragraphId, text, title, params, config);
|
||||
|
||||
persistAndExecuteSingleParagraph(conn, note, p);
|
||||
}
|
||||
}
|
||||
|
||||
private void runParagraph(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
|
||||
Message fromMessage) throws IOException {
|
||||
final String paragraphId = (String) fromMessage.get("id");
|
||||
if (paragraphId == null) {
|
||||
return;
|
||||
|
|
@ -1550,30 +1590,29 @@ public class NotebookServer extends WebSocketServlet
|
|||
return;
|
||||
}
|
||||
|
||||
Paragraph p = note.getParagraph(paragraphId);
|
||||
String text = (String) fromMessage.get("paragraph");
|
||||
p.setText(text);
|
||||
p.setTitle((String) fromMessage.get("title"));
|
||||
AuthenticationInfo subject =
|
||||
new AuthenticationInfo(fromMessage.principal, fromMessage.ticket);
|
||||
p.setAuthenticationInfo(subject);
|
||||
|
||||
String title = (String) fromMessage.get("title");
|
||||
Map<String, Object> params = (Map<String, Object>) fromMessage.get("params");
|
||||
p.settings.setParams(params);
|
||||
Map<String, Object> config = (Map<String, Object>) fromMessage.get("config");
|
||||
p.setConfig(config);
|
||||
Paragraph p = setParagraphUsingMessage(note, fromMessage, paragraphId,
|
||||
text, title, params, config);
|
||||
|
||||
persistAndExecuteSingleParagraph(conn, note, p);
|
||||
}
|
||||
|
||||
private void persistAndExecuteSingleParagraph(NotebookSocket conn,
|
||||
Note note, Paragraph p) throws IOException {
|
||||
// if it's the last paragraph and empty, let's add a new one
|
||||
boolean isTheLastParagraph = note.isLastParagraph(p.getId());
|
||||
if (!(text.trim().equals(p.getMagic()) ||
|
||||
Strings.isNullOrEmpty(text)) &&
|
||||
if (!(p.getText().trim().equals(p.getMagic()) ||
|
||||
Strings.isNullOrEmpty(p.getText())) &&
|
||||
isTheLastParagraph) {
|
||||
Paragraph newPara = note.addParagraph(subject);
|
||||
Paragraph newPara = note.addParagraph(p.getAuthenticationInfo());
|
||||
broadcastNewParagraph(note, newPara);
|
||||
}
|
||||
|
||||
try {
|
||||
note.persist(subject);
|
||||
note.persist(p.getAuthenticationInfo());
|
||||
} catch (FileSystemException ex) {
|
||||
LOG.error("Exception from run", ex);
|
||||
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
|
||||
|
|
@ -1584,7 +1623,7 @@ public class NotebookServer extends WebSocketServlet
|
|||
}
|
||||
|
||||
try {
|
||||
note.run(paragraphId);
|
||||
note.run(p.getId());
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Exception from run", ex);
|
||||
if (p != null) {
|
||||
|
|
@ -1595,6 +1634,21 @@ public class NotebookServer extends WebSocketServlet
|
|||
}
|
||||
}
|
||||
|
||||
private Paragraph setParagraphUsingMessage(Note note, Message fromMessage, String paragraphId,
|
||||
String text, String title, Map<String, Object> params,
|
||||
Map<String, Object> config) {
|
||||
Paragraph p = note.getParagraph(paragraphId);
|
||||
p.setText(text);
|
||||
p.setTitle(title);
|
||||
AuthenticationInfo subject =
|
||||
new AuthenticationInfo(fromMessage.principal, fromMessage.ticket);
|
||||
p.setAuthenticationInfo(subject);
|
||||
p.settings.setParams(params);
|
||||
p.setConfig(config);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private void sendAllConfigurations(NotebookSocket conn, HashSet<String> userAndRoles,
|
||||
Notebook notebook) throws IOException {
|
||||
ZeppelinConfiguration conf = notebook.getConf();
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ public class ParagraphActionsIT extends AbstractZeppelinIT {
|
|||
driver.findElement(By.xpath(getParagraphXPath(1) + "//span[@class='icon-control-play shortcut-icon']")).isDisplayed(), CoreMatchers.equalTo(false)
|
||||
);
|
||||
|
||||
driver.findElement(By.xpath(".//*[@id='main']//button[@ng-click='runNote()']")).sendKeys(Keys.ENTER);
|
||||
driver.findElement(By.xpath(".//*[@id='main']//button[contains(@ng-click, 'runAllParagraphs')]")).sendKeys(Keys.ENTER);
|
||||
ZeppelinITUtils.sleep(1000, true);
|
||||
driver.findElement(By.xpath("//div[@class='modal-dialog'][contains(.,'Run all paragraphs?')]" +
|
||||
"//div[@class='modal-footer']//button[contains(.,'OK')]")).click();
|
||||
|
|
|
|||
|
|
@ -11,52 +11,50 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('MainCtrl', MainCtrl);
|
||||
angular.module('zeppelinWebApp').controller('MainCtrl', MainCtrl);
|
||||
|
||||
MainCtrl.$inject = ['$scope', '$rootScope', '$window', 'arrayOrderingSrv'];
|
||||
MainCtrl.$inject = ['$scope', '$rootScope', '$window', 'arrayOrderingSrv'];
|
||||
|
||||
function MainCtrl($scope, $rootScope, $window, arrayOrderingSrv) {
|
||||
$scope.looknfeel = 'default';
|
||||
function MainCtrl($scope, $rootScope, $window, arrayOrderingSrv) {
|
||||
$scope.looknfeel = 'default';
|
||||
|
||||
var init = function() {
|
||||
$scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true : false);
|
||||
};
|
||||
var init = function() {
|
||||
$scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true : false);
|
||||
};
|
||||
|
||||
init();
|
||||
init();
|
||||
|
||||
$rootScope.$on('setIframe', function(event, data) {
|
||||
if (!event.defaultPrevented) {
|
||||
$scope.asIframe = data;
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
$rootScope.$on('setIframe', function(event, data) {
|
||||
if (!event.defaultPrevented) {
|
||||
$scope.asIframe = data;
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('setLookAndFeel', function(event, data) {
|
||||
if (!event.defaultPrevented && data && data !== '' && data !== $scope.looknfeel) {
|
||||
$scope.looknfeel = data;
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
$rootScope.$on('setLookAndFeel', function(event, data) {
|
||||
if (!event.defaultPrevented && data && data !== '' && data !== $scope.looknfeel) {
|
||||
$scope.looknfeel = data;
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Set The lookAndFeel to default on every page
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
$rootScope.$broadcast('setLookAndFeel', 'default');
|
||||
});
|
||||
// Set The lookAndFeel to default on every page
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
$rootScope.$broadcast('setLookAndFeel', 'default');
|
||||
});
|
||||
|
||||
$rootScope.noteName = function(note) {
|
||||
if (!_.isEmpty(note)) {
|
||||
return arrayOrderingSrv.getNoteName(note);
|
||||
}
|
||||
};
|
||||
$rootScope.noteName = function(note) {
|
||||
if (!_.isEmpty(note)) {
|
||||
return arrayOrderingSrv.getNoteName(note);
|
||||
}
|
||||
};
|
||||
|
||||
BootstrapDialog.defaultOptions.onshown = function() {
|
||||
angular.element('#' + this.id).find('.btn:last').focus();
|
||||
};
|
||||
BootstrapDialog.defaultOptions.onshown = function() {
|
||||
angular.element('#' + this.id).find('.btn:last').focus();
|
||||
};
|
||||
|
||||
// Remove BootstrapDialog animation
|
||||
BootstrapDialog.configDefaultOptions({animate: false});
|
||||
}
|
||||
// Remove BootstrapDialog animation
|
||||
BootstrapDialog.configDefaultOptions({animate: false});
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -14,129 +14,128 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
var zeppelinWebApp = angular.module('zeppelinWebApp', [
|
||||
'ngCookies',
|
||||
'ngAnimate',
|
||||
'ngRoute',
|
||||
'ngSanitize',
|
||||
'angular-websocket',
|
||||
'ui.ace',
|
||||
'ui.bootstrap',
|
||||
'as.sortable',
|
||||
'ngTouch',
|
||||
'ngDragDrop',
|
||||
'angular.filter',
|
||||
'monospaced.elastic',
|
||||
'puElasticInput',
|
||||
'xeditable',
|
||||
'ngToast',
|
||||
'focus-if',
|
||||
'ngResource',
|
||||
'ngclipboard'
|
||||
])
|
||||
.filter('breakFilter', function() {
|
||||
return function(text) {
|
||||
if (!!text) {
|
||||
return text.replace(/\n/g, '<br />');
|
||||
}
|
||||
};
|
||||
})
|
||||
.config(function($httpProvider, $routeProvider, ngToastProvider) {
|
||||
// withCredentials when running locally via grunt
|
||||
$httpProvider.defaults.withCredentials = true;
|
||||
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
templateUrl: 'app/home/home.html'
|
||||
})
|
||||
.when('/notebook/:noteId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/paragraph?=:paragraphId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/paragraph/:paragraphId?', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/revision/:revisionId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/jobmanager', {
|
||||
templateUrl: 'app/jobmanager/jobmanager.html',
|
||||
controller: 'JobmanagerCtrl'
|
||||
})
|
||||
.when('/interpreter', {
|
||||
templateUrl: 'app/interpreter/interpreter.html',
|
||||
controller: 'InterpreterCtrl'
|
||||
})
|
||||
.when('/notebookRepos', {
|
||||
templateUrl: 'app/notebookRepos/notebookRepos.html',
|
||||
controller: 'NotebookReposCtrl',
|
||||
controllerAs: 'noterepo'
|
||||
})
|
||||
.when('/credential', {
|
||||
templateUrl: 'app/credential/credential.html',
|
||||
controller: 'CredentialCtrl'
|
||||
})
|
||||
.when('/configuration', {
|
||||
templateUrl: 'app/configuration/configuration.html',
|
||||
controller: 'ConfigurationCtrl'
|
||||
})
|
||||
.when('/search/:searchTerm', {
|
||||
templateUrl: 'app/search/result-list.html',
|
||||
controller: 'SearchResultCtrl'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/'
|
||||
});
|
||||
|
||||
ngToastProvider.configure({
|
||||
dismissButton: true,
|
||||
dismissOnClick: false,
|
||||
combineDuplications: true,
|
||||
timeout: 6000
|
||||
});
|
||||
})
|
||||
.constant('TRASH_FOLDER_ID', '~Trash');
|
||||
|
||||
function auth() {
|
||||
var $http = angular.injector(['ng']).get('$http');
|
||||
var baseUrlSrv = angular.injector(['zeppelinWebApp']).get('baseUrlSrv');
|
||||
var zeppelinWebApp = angular.module('zeppelinWebApp', [
|
||||
'ngCookies',
|
||||
'ngAnimate',
|
||||
'ngRoute',
|
||||
'ngSanitize',
|
||||
'angular-websocket',
|
||||
'ui.ace',
|
||||
'ui.bootstrap',
|
||||
'as.sortable',
|
||||
'ngTouch',
|
||||
'ngDragDrop',
|
||||
'angular.filter',
|
||||
'monospaced.elastic',
|
||||
'puElasticInput',
|
||||
'xeditable',
|
||||
'ngToast',
|
||||
'focus-if',
|
||||
'ngResource',
|
||||
'ngclipboard'
|
||||
])
|
||||
.filter('breakFilter', function() {
|
||||
return function(text) {
|
||||
if (!!text) {
|
||||
return text.replace(/\n/g, '<br />');
|
||||
}
|
||||
};
|
||||
})
|
||||
.config(function($httpProvider, $routeProvider, ngToastProvider) {
|
||||
// withCredentials when running locally via grunt
|
||||
$http.defaults.withCredentials = true;
|
||||
jQuery.ajaxSetup({
|
||||
dataType: 'json',
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
crossDomain: true
|
||||
});
|
||||
return $http.get(baseUrlSrv.getRestApiBase() + '/security/ticket').then(function(response) {
|
||||
zeppelinWebApp.run(function($rootScope) {
|
||||
$rootScope.ticket = angular.fromJson(response.data).body;
|
||||
});
|
||||
}, function(errorResponse) {
|
||||
// Handle error case
|
||||
});
|
||||
}
|
||||
$httpProvider.defaults.withCredentials = true;
|
||||
|
||||
function bootstrapApplication() {
|
||||
zeppelinWebApp.run(function($rootScope, $location) {
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
if (!$rootScope.ticket && next.$$route && !next.$$route.publicAccess) {
|
||||
$location.path('/');
|
||||
}
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
templateUrl: 'app/home/home.html'
|
||||
})
|
||||
.when('/notebook/:noteId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/paragraph?=:paragraphId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/paragraph/:paragraphId?', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/revision/:revisionId', {
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/jobmanager', {
|
||||
templateUrl: 'app/jobmanager/jobmanager.html',
|
||||
controller: 'JobmanagerCtrl'
|
||||
})
|
||||
.when('/interpreter', {
|
||||
templateUrl: 'app/interpreter/interpreter.html',
|
||||
controller: 'InterpreterCtrl'
|
||||
})
|
||||
.when('/notebookRepos', {
|
||||
templateUrl: 'app/notebookRepos/notebookRepos.html',
|
||||
controller: 'NotebookReposCtrl',
|
||||
controllerAs: 'noterepo'
|
||||
})
|
||||
.when('/credential', {
|
||||
templateUrl: 'app/credential/credential.html',
|
||||
controller: 'CredentialCtrl'
|
||||
})
|
||||
.when('/configuration', {
|
||||
templateUrl: 'app/configuration/configuration.html',
|
||||
controller: 'ConfigurationCtrl'
|
||||
})
|
||||
.when('/search/:searchTerm', {
|
||||
templateUrl: 'app/search/result-list.html',
|
||||
controller: 'SearchResultCtrl'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/'
|
||||
});
|
||||
});
|
||||
angular.bootstrap(document, ['zeppelinWebApp']);
|
||||
}
|
||||
|
||||
angular.element(document).ready(function() {
|
||||
auth().then(bootstrapApplication);
|
||||
ngToastProvider.configure({
|
||||
dismissButton: true,
|
||||
dismissOnClick: false,
|
||||
combineDuplications: true,
|
||||
timeout: 6000
|
||||
});
|
||||
})
|
||||
.constant('TRASH_FOLDER_ID', '~Trash');
|
||||
|
||||
function auth() {
|
||||
var $http = angular.injector(['ng']).get('$http');
|
||||
var baseUrlSrv = angular.injector(['zeppelinWebApp']).get('baseUrlSrv');
|
||||
// withCredentials when running locally via grunt
|
||||
$http.defaults.withCredentials = true;
|
||||
jQuery.ajaxSetup({
|
||||
dataType: 'json',
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
crossDomain: true
|
||||
});
|
||||
}());
|
||||
return $http.get(baseUrlSrv.getRestApiBase() + '/security/ticket').then(function(response) {
|
||||
zeppelinWebApp.run(function($rootScope) {
|
||||
$rootScope.ticket = angular.fromJson(response.data).body;
|
||||
});
|
||||
}, function(errorResponse) {
|
||||
// Handle error case
|
||||
});
|
||||
}
|
||||
|
||||
function bootstrapApplication() {
|
||||
zeppelinWebApp.run(function($rootScope, $location) {
|
||||
$rootScope.$on('$routeChangeStart', function(event, next, current) {
|
||||
if (!$rootScope.ticket && next.$$route && !next.$$route.publicAccess) {
|
||||
$location.path('/');
|
||||
}
|
||||
});
|
||||
});
|
||||
angular.bootstrap(document, ['zeppelinWebApp']);
|
||||
}
|
||||
|
||||
angular.element(document).ready(function() {
|
||||
auth().then(bootstrapApplication);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,41 +11,39 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('ConfigurationCtrl', ConfigurationCtrl);
|
||||
angular.module('zeppelinWebApp').controller('ConfigurationCtrl', ConfigurationCtrl);
|
||||
|
||||
ConfigurationCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
|
||||
ConfigurationCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
|
||||
|
||||
function ConfigurationCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
|
||||
$scope.configrations = [];
|
||||
$scope._ = _;
|
||||
ngToast.dismiss();
|
||||
function ConfigurationCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
|
||||
$scope.configrations = [];
|
||||
$scope._ = _;
|
||||
ngToast.dismiss();
|
||||
|
||||
var getConfigurations = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/configurations/all').
|
||||
success(function(data, status, headers, config) {
|
||||
$scope.configurations = data.body;
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
var getConfigurations = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/configurations/all').
|
||||
success(function(data, status, headers, config) {
|
||||
$scope.configurations = data.body;
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
var init = function() {
|
||||
getConfigurations();
|
||||
};
|
||||
var init = function() {
|
||||
getConfigurations();
|
||||
};
|
||||
|
||||
init();
|
||||
}
|
||||
})();
|
||||
init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,88 +11,87 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('CredentialCtrl', CredentialCtrl);
|
||||
angular.module('zeppelinWebApp').controller('CredentialCtrl', CredentialCtrl);
|
||||
|
||||
CredentialCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
|
||||
CredentialCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
|
||||
|
||||
function CredentialCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
|
||||
$scope._ = _;
|
||||
ngToast.dismiss();
|
||||
function CredentialCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
|
||||
$scope._ = _;
|
||||
ngToast.dismiss();
|
||||
|
||||
$scope.credentialInfo = [];
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
$scope.availableInterpreters = [];
|
||||
$scope.credentialInfo = [];
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
$scope.availableInterpreters = [];
|
||||
|
||||
var getCredentialInfo = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/credential').
|
||||
success(function(data, status, headers, config) {
|
||||
$scope.credentialInfo = _.map(data.body.userCredentials, function(value, prop) {
|
||||
return {entity: prop, password: value.password, username: value.username};
|
||||
});
|
||||
console.log('Success %o %o', status, $scope.credentialInfo);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
var getCredentialInfo = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/credential').
|
||||
success(function(data, status, headers, config) {
|
||||
$scope.credentialInfo = _.map(data.body.userCredentials, function(value, prop) {
|
||||
return {entity: prop, password: value.password, username: value.username};
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addNewCredentialInfo = function() {
|
||||
if ($scope.entity && _.isEmpty($scope.entity.trim()) &&
|
||||
$scope.username && _.isEmpty($scope.username.trim())) {
|
||||
console.log('Success %o %o', status, $scope.credentialInfo);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'Username \\ Entity can not be empty.',
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
return;
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
var newCredential = {
|
||||
'entity': $scope.entity,
|
||||
'username': $scope.username,
|
||||
'password': $scope.password
|
||||
};
|
||||
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/credential', newCredential).
|
||||
success(function(data, status, headers, config) {
|
||||
ngToast.success({
|
||||
content: 'Successfully saved credentials.',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
$scope.credentialInfo.push(newCredential);
|
||||
resetCredentialInfo();
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
console.log('Success %o %o', status, data.message);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
ngToast.danger({
|
||||
content: 'Error saving credentials',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
console.log('Error %o %o', status, data.message);
|
||||
$scope.addNewCredentialInfo = function() {
|
||||
if ($scope.entity && _.isEmpty($scope.entity.trim()) &&
|
||||
$scope.username && _.isEmpty($scope.username.trim())) {
|
||||
ngToast.danger({
|
||||
content: 'Username \\ Entity can not be empty.',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var newCredential = {
|
||||
'entity': $scope.entity,
|
||||
'username': $scope.username,
|
||||
'password': $scope.password
|
||||
};
|
||||
|
||||
var getAvailableInterpreters = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/interpreter/setting')
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/credential', newCredential).
|
||||
success(function(data, status, headers, config) {
|
||||
ngToast.success({
|
||||
content: 'Successfully saved credentials.',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
$scope.credentialInfo.push(newCredential);
|
||||
resetCredentialInfo();
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
console.log('Success %o %o', status, data.message);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
ngToast.danger({
|
||||
content: 'Error saving credentials',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
var getAvailableInterpreters = function() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/interpreter/setting')
|
||||
.success(function(data, status, headers, config) {
|
||||
for (var setting = 0; setting < data.body.length; setting++) {
|
||||
$scope.availableInterpreters.push(
|
||||
data.body[setting].group + '.' + data.body[setting].name);
|
||||
data.body[setting].group + '.' + data.body[setting].name);
|
||||
}
|
||||
angular.element('#entityname').autocomplete({
|
||||
source: $scope.availableInterpreters,
|
||||
|
|
@ -102,91 +101,90 @@
|
|||
}
|
||||
});
|
||||
}).error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleAddNewCredentialInfo = function() {
|
||||
if ($scope.showAddNewCredentialInfo) {
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
} else {
|
||||
$scope.showAddNewCredentialInfo = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelCredentialInfo = function() {
|
||||
$scope.toggleAddNewCredentialInfo = function() {
|
||||
if ($scope.showAddNewCredentialInfo) {
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
resetCredentialInfo();
|
||||
} else {
|
||||
$scope.showAddNewCredentialInfo = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelCredentialInfo = function() {
|
||||
$scope.showAddNewCredentialInfo = false;
|
||||
resetCredentialInfo();
|
||||
};
|
||||
|
||||
var resetCredentialInfo = function() {
|
||||
$scope.entity = '';
|
||||
$scope.username = '';
|
||||
$scope.password = '';
|
||||
};
|
||||
|
||||
$scope.copyOriginCredentialsInfo = function() {
|
||||
ngToast.info({
|
||||
content: 'Since entity is a unique key, you can edit only username & password',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateCredentialInfo = function(form, data, entity) {
|
||||
var request = {
|
||||
entity: entity,
|
||||
username: data.username,
|
||||
password: data.password
|
||||
};
|
||||
|
||||
var resetCredentialInfo = function() {
|
||||
$scope.entity = '';
|
||||
$scope.username = '';
|
||||
$scope.password = '';
|
||||
};
|
||||
|
||||
$scope.copyOriginCredentialsInfo = function() {
|
||||
ngToast.info({
|
||||
content: 'Since entity is a unique key, you can edit only username & password',
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/credential/', request).
|
||||
success(function(data, status, headers, config) {
|
||||
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
|
||||
$scope.credentialInfo[index] = request;
|
||||
return true;
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
ngToast.danger({
|
||||
content: 'We couldn\'t save the credential',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
};
|
||||
form.$show();
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.updateCredentialInfo = function(form, data, entity) {
|
||||
var request = {
|
||||
entity: entity,
|
||||
username: data.username,
|
||||
password: data.password
|
||||
};
|
||||
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/credential/', request).
|
||||
success(function(data, status, headers, config) {
|
||||
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
|
||||
$scope.credentialInfo[index] = request;
|
||||
return true;
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
ngToast.danger({
|
||||
content: 'We couldn\'t save the credential',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
form.$show();
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.removeCredentialInfo = function(entity) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: '',
|
||||
message: 'Do you want to delete this credential information?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http.delete(baseUrlSrv.getRestApiBase() + '/credential/' + entity).
|
||||
success(function(data, status, headers, config) {
|
||||
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
|
||||
$scope.credentialInfo.splice(index, 1);
|
||||
console.log('Success %o %o', status, data.message);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
}
|
||||
$scope.removeCredentialInfo = function(entity) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: '',
|
||||
message: 'Do you want to delete this credential information?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http.delete(baseUrlSrv.getRestApiBase() + '/credential/' + entity).
|
||||
success(function(data, status, headers, config) {
|
||||
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
|
||||
$scope.credentialInfo.splice(index, 1);
|
||||
console.log('Success %o %o', status, data.message);
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var init = function() {
|
||||
getAvailableInterpreters();
|
||||
getCredentialInfo();
|
||||
};
|
||||
var init = function() {
|
||||
getAvailableInterpreters();
|
||||
getCredentialInfo();
|
||||
};
|
||||
|
||||
init();
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,126 +11,124 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('HomeCtrl', HomeCtrl);
|
||||
angular.module('zeppelinWebApp').controller('HomeCtrl', HomeCtrl);
|
||||
|
||||
HomeCtrl.$inject = [
|
||||
'$scope',
|
||||
'noteListDataFactory',
|
||||
'websocketMsgSrv',
|
||||
'$rootScope',
|
||||
'arrayOrderingSrv',
|
||||
'ngToast',
|
||||
'noteActionSrv',
|
||||
'TRASH_FOLDER_ID'
|
||||
];
|
||||
HomeCtrl.$inject = [
|
||||
'$scope',
|
||||
'noteListDataFactory',
|
||||
'websocketMsgSrv',
|
||||
'$rootScope',
|
||||
'arrayOrderingSrv',
|
||||
'ngToast',
|
||||
'noteActionSrv',
|
||||
'TRASH_FOLDER_ID'
|
||||
];
|
||||
|
||||
function HomeCtrl($scope, noteListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv,
|
||||
ngToast, noteActionSrv, TRASH_FOLDER_ID) {
|
||||
ngToast.dismiss();
|
||||
var vm = this;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
vm.arrayOrderingSrv = arrayOrderingSrv;
|
||||
function HomeCtrl($scope, noteListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv,
|
||||
ngToast, noteActionSrv, TRASH_FOLDER_ID) {
|
||||
ngToast.dismiss();
|
||||
var vm = this;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
vm.arrayOrderingSrv = arrayOrderingSrv;
|
||||
|
||||
vm.notebookHome = false;
|
||||
if ($rootScope.ticket !== undefined) {
|
||||
vm.notebookHome = false;
|
||||
if ($rootScope.ticket !== undefined) {
|
||||
vm.staticHome = false;
|
||||
} else {
|
||||
vm.staticHome = true;
|
||||
}
|
||||
|
||||
$scope.isReloading = false;
|
||||
$scope.TRASH_FOLDER_ID = TRASH_FOLDER_ID;
|
||||
|
||||
var initHome = function() {
|
||||
websocketMsgSrv.getHomeNote();
|
||||
};
|
||||
|
||||
initHome();
|
||||
|
||||
$scope.reloadNoteList = function() {
|
||||
websocketMsgSrv.reloadAllNotesFromRepo();
|
||||
$scope.isReloadingNotes = true;
|
||||
};
|
||||
|
||||
$scope.toggleFolderNode = function(node) {
|
||||
node.hidden = !node.hidden;
|
||||
};
|
||||
|
||||
angular.element('#loginModal').on('hidden.bs.modal', function(e) {
|
||||
$rootScope.$broadcast('initLoginValues');
|
||||
});
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
$scope.isReloadingNotes = false;
|
||||
});
|
||||
|
||||
$scope.$on('setNoteContent', function(event, note) {
|
||||
if (note) {
|
||||
vm.note = note;
|
||||
|
||||
// initialize look And Feel
|
||||
$rootScope.$broadcast('setLookAndFeel', 'home');
|
||||
|
||||
// make it read only
|
||||
vm.viewOnly = true;
|
||||
|
||||
vm.notebookHome = true;
|
||||
vm.staticHome = false;
|
||||
} else {
|
||||
vm.staticHome = true;
|
||||
vm.notebookHome = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.isReloading = false;
|
||||
$scope.TRASH_FOLDER_ID = TRASH_FOLDER_ID;
|
||||
$scope.renameNote = function(node) {
|
||||
noteActionSrv.renameNote(node.id, node.path);
|
||||
};
|
||||
|
||||
var initHome = function() {
|
||||
websocketMsgSrv.getHomeNote();
|
||||
};
|
||||
$scope.moveNoteToTrash = function(noteId) {
|
||||
noteActionSrv.moveNoteToTrash(noteId, false);
|
||||
};
|
||||
|
||||
initHome();
|
||||
$scope.moveFolderToTrash = function(folderId) {
|
||||
noteActionSrv.moveFolderToTrash(folderId);
|
||||
};
|
||||
|
||||
$scope.reloadNoteList = function() {
|
||||
websocketMsgSrv.reloadAllNotesFromRepo();
|
||||
$scope.isReloadingNotes = true;
|
||||
};
|
||||
$scope.restoreNote = function(noteId) {
|
||||
websocketMsgSrv.restoreNote(noteId);
|
||||
};
|
||||
|
||||
$scope.toggleFolderNode = function(node) {
|
||||
node.hidden = !node.hidden;
|
||||
};
|
||||
$scope.restoreFolder = function(folderId) {
|
||||
websocketMsgSrv.restoreFolder(folderId);
|
||||
};
|
||||
|
||||
angular.element('#loginModal').on('hidden.bs.modal', function(e) {
|
||||
$rootScope.$broadcast('initLoginValues');
|
||||
});
|
||||
$scope.restoreAll = function() {
|
||||
noteActionSrv.restoreAll();
|
||||
};
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
$scope.renameFolder = function(node) {
|
||||
noteActionSrv.renameFolder(node.id);
|
||||
};
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
$scope.isReloadingNotes = false;
|
||||
});
|
||||
$scope.removeNote = function(noteId) {
|
||||
noteActionSrv.removeNote(noteId, false);
|
||||
};
|
||||
|
||||
$scope.$on('setNoteContent', function(event, note) {
|
||||
if (note) {
|
||||
vm.note = note;
|
||||
$scope.removeFolder = function(folderId) {
|
||||
noteActionSrv.removeFolder(folderId);
|
||||
};
|
||||
|
||||
// initialize look And Feel
|
||||
$rootScope.$broadcast('setLookAndFeel', 'home');
|
||||
$scope.emptyTrash = function() {
|
||||
noteActionSrv.emptyTrash();
|
||||
};
|
||||
|
||||
// make it read only
|
||||
vm.viewOnly = true;
|
||||
|
||||
vm.notebookHome = true;
|
||||
vm.staticHome = false;
|
||||
} else {
|
||||
vm.staticHome = true;
|
||||
vm.notebookHome = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.renameNote = function(node) {
|
||||
noteActionSrv.renameNote(node.id, node.path);
|
||||
};
|
||||
|
||||
$scope.moveNoteToTrash = function(noteId) {
|
||||
noteActionSrv.moveNoteToTrash(noteId, false);
|
||||
};
|
||||
|
||||
$scope.moveFolderToTrash = function(folderId) {
|
||||
noteActionSrv.moveFolderToTrash(folderId);
|
||||
};
|
||||
|
||||
$scope.restoreNote = function(noteId) {
|
||||
websocketMsgSrv.restoreNote(noteId);
|
||||
};
|
||||
|
||||
$scope.restoreFolder = function(folderId) {
|
||||
websocketMsgSrv.restoreFolder(folderId);
|
||||
};
|
||||
|
||||
$scope.restoreAll = function() {
|
||||
noteActionSrv.restoreAll();
|
||||
};
|
||||
|
||||
$scope.renameFolder = function(node) {
|
||||
noteActionSrv.renameFolder(node.id);
|
||||
};
|
||||
|
||||
$scope.removeNote = function(noteId) {
|
||||
noteActionSrv.removeNote(noteId, false);
|
||||
};
|
||||
|
||||
$scope.removeFolder = function(folderId) {
|
||||
noteActionSrv.removeFolder(folderId);
|
||||
};
|
||||
|
||||
$scope.emptyTrash = function() {
|
||||
noteActionSrv.emptyTrash();
|
||||
};
|
||||
|
||||
$scope.clearAllParagraphOutput = function(noteId) {
|
||||
noteActionSrv.clearAllParagraphOutput(noteId);
|
||||
};
|
||||
}
|
||||
})();
|
||||
$scope.clearAllParagraphOutput = function(noteId) {
|
||||
noteActionSrv.clearAllParagraphOutput(noteId);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,13 +381,13 @@ a.navbar-brand:hover {
|
|||
}
|
||||
|
||||
.zeppelin {
|
||||
background: url('/assets/images/zepLogo.png') no-repeat right;
|
||||
background: url('../assets/images/zepLogo.png') no-repeat right;
|
||||
height: 380px;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.zeppelin2 {
|
||||
background: url('/assets/images/zepLogo.png') no-repeat right;
|
||||
background: url('../assets/images/zepLogo.png') no-repeat right;
|
||||
background-position-y: 12px;
|
||||
height: 380px;
|
||||
opacity: 0.2;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,15 +11,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').filter('sortByKey', sortByKey);
|
||||
angular.module('zeppelinWebApp').filter('sortByKey', sortByKey);
|
||||
|
||||
function sortByKey() {
|
||||
return function(properties) {
|
||||
var sortedKeys = properties ? Object.keys(properties) : [];
|
||||
return sortedKeys.sort();
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
function sortByKey() {
|
||||
return function(properties) {
|
||||
var sortedKeys = properties ? Object.keys(properties) : [];
|
||||
return sortedKeys.sort();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,167 +11,165 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp')
|
||||
.controller('JobmanagerCtrl', JobmanagerCtrl);
|
||||
angular.module('zeppelinWebApp')
|
||||
.controller('JobmanagerCtrl', JobmanagerCtrl);
|
||||
|
||||
JobmanagerCtrl.$inject = ['$scope', 'websocketMsgSrv', '$interval', 'ngToast', '$q', '$timeout', 'jobManagerFilter'];
|
||||
JobmanagerCtrl.$inject = ['$scope', 'websocketMsgSrv', '$interval', 'ngToast', '$q', '$timeout', 'jobManagerFilter'];
|
||||
|
||||
function JobmanagerCtrl($scope, websocketMsgSrv, $interval, ngToast, $q, $timeout, jobManagerFilter) {
|
||||
ngToast.dismiss();
|
||||
var asyncNotebookJobFilter = function(jobInfomations, filterConfig) {
|
||||
return $q(function(resolve, reject) {
|
||||
$scope.JobInfomationsByFilter = $scope.jobTypeFilter(jobInfomations, filterConfig);
|
||||
resolve($scope.JobInfomationsByFilter);
|
||||
function JobmanagerCtrl($scope, websocketMsgSrv, $interval, ngToast, $q, $timeout, jobManagerFilter) {
|
||||
ngToast.dismiss();
|
||||
var asyncNotebookJobFilter = function(jobInfomations, filterConfig) {
|
||||
return $q(function(resolve, reject) {
|
||||
$scope.JobInfomationsByFilter = $scope.jobTypeFilter(jobInfomations, filterConfig);
|
||||
resolve($scope.JobInfomationsByFilter);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.doFiltering = function(jobInfomations, filterConfig) {
|
||||
asyncNotebookJobFilter(jobInfomations, filterConfig).then(
|
||||
function() {
|
||||
// success
|
||||
$scope.isLoadingFilter = false;
|
||||
},
|
||||
function() {
|
||||
// failed
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
$scope.doFiltering = function(jobInfomations, filterConfig) {
|
||||
asyncNotebookJobFilter(jobInfomations, filterConfig).then(
|
||||
function() {
|
||||
// success
|
||||
$scope.isLoadingFilter = false;
|
||||
},
|
||||
function() {
|
||||
// failed
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterValueToName = function(filterValue, maxStringLength) {
|
||||
if ($scope.activeInterpreters === undefined) {
|
||||
return;
|
||||
$scope.filterValueToName = function(filterValue, maxStringLength) {
|
||||
if ($scope.activeInterpreters === undefined) {
|
||||
return;
|
||||
}
|
||||
var index = _.findIndex($scope.activeInterpreters, {value: filterValue});
|
||||
if ($scope.activeInterpreters[index].name !== undefined) {
|
||||
if (maxStringLength !== undefined && maxStringLength > $scope.activeInterpreters[index].name) {
|
||||
return $scope.activeInterpreters[index].name.substr(0, maxStringLength - 3) + '...';
|
||||
}
|
||||
var index = _.findIndex($scope.activeInterpreters, {value: filterValue});
|
||||
if ($scope.activeInterpreters[index].name !== undefined) {
|
||||
if (maxStringLength !== undefined && maxStringLength > $scope.activeInterpreters[index].name) {
|
||||
return $scope.activeInterpreters[index].name.substr(0, maxStringLength - 3) + '...';
|
||||
}
|
||||
return $scope.activeInterpreters[index].name;
|
||||
} else {
|
||||
return 'Interpreter is not set';
|
||||
}
|
||||
};
|
||||
return $scope.activeInterpreters[index].name;
|
||||
} else {
|
||||
return 'Interpreter is not set';
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setFilterValue = function(filterValue) {
|
||||
$scope.filterConfig.filterValueInterpreter = filterValue;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
$scope.setFilterValue = function(filterValue) {
|
||||
$scope.filterConfig.filterValueInterpreter = filterValue;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
|
||||
$scope.onChangeRunJobToAlwaysTopToggle = function() {
|
||||
$scope.filterConfig.isRunningAlwaysTop = !$scope.filterConfig.isRunningAlwaysTop;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
$scope.onChangeRunJobToAlwaysTopToggle = function() {
|
||||
$scope.filterConfig.isRunningAlwaysTop = !$scope.filterConfig.isRunningAlwaysTop;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
|
||||
$scope.onChangeSortAsc = function() {
|
||||
$scope.filterConfig.isSortByAsc = !$scope.filterConfig.isSortByAsc;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
$scope.onChangeSortAsc = function() {
|
||||
$scope.filterConfig.isSortByAsc = !$scope.filterConfig.isSortByAsc;
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
};
|
||||
|
||||
$scope.doFilterInputTyping = function(keyEvent, jobInfomations, filterConfig) {
|
||||
var RETURN_KEY_CODE = 13;
|
||||
$timeout.cancel($scope.dofilterTimeoutObject);
|
||||
$scope.isActiveSearchTimer = true;
|
||||
$scope.dofilterTimeoutObject = $timeout(function() {
|
||||
$scope.doFiltering(jobInfomations, filterConfig);
|
||||
$scope.isActiveSearchTimer = false;
|
||||
}, 10000);
|
||||
if (keyEvent.which === RETURN_KEY_CODE) {
|
||||
$timeout.cancel($scope.dofilterTimeoutObject);
|
||||
$scope.doFiltering(jobInfomations, filterConfig);
|
||||
$scope.isActiveSearchTimer = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.doForceFilterInputTyping = function(keyEvent, jobInfomations, filterConfig) {
|
||||
$scope.doFilterInputTyping = function(keyEvent, jobInfomations, filterConfig) {
|
||||
var RETURN_KEY_CODE = 13;
|
||||
$timeout.cancel($scope.dofilterTimeoutObject);
|
||||
$scope.isActiveSearchTimer = true;
|
||||
$scope.dofilterTimeoutObject = $timeout(function() {
|
||||
$scope.doFiltering(jobInfomations, filterConfig);
|
||||
$scope.isActiveSearchTimer = false;
|
||||
}, 10000);
|
||||
if (keyEvent.which === RETURN_KEY_CODE) {
|
||||
$timeout.cancel($scope.dofilterTimeoutObject);
|
||||
$scope.doFiltering(jobInfomations, filterConfig);
|
||||
$scope.isActiveSearchTimer = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.doForceFilterInputTyping = function(keyEvent, jobInfomations, filterConfig) {
|
||||
$timeout.cancel($scope.dofilterTimeoutObject);
|
||||
$scope.doFiltering(jobInfomations, filterConfig);
|
||||
$scope.isActiveSearchTimer = false;
|
||||
};
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.isLoadingFilter = true;
|
||||
$scope.jobInfomations = [];
|
||||
$scope.JobInfomationsByFilter = $scope.jobInfomations;
|
||||
$scope.filterConfig = {
|
||||
isRunningAlwaysTop: true,
|
||||
filterValueNotebookName: '',
|
||||
filterValueInterpreter: '*',
|
||||
isSortByAsc: true
|
||||
};
|
||||
$scope.jobTypeFilter = jobManagerFilter;
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.isLoadingFilter = true;
|
||||
$scope.jobInfomations = [];
|
||||
$scope.JobInfomationsByFilter = $scope.jobInfomations;
|
||||
$scope.filterConfig = {
|
||||
isRunningAlwaysTop: true,
|
||||
filterValueNotebookName: '',
|
||||
filterValueInterpreter: '*',
|
||||
isSortByAsc: true
|
||||
};
|
||||
$scope.jobTypeFilter = jobManagerFilter;
|
||||
websocketMsgSrv.getNoteJobsList();
|
||||
|
||||
websocketMsgSrv.getNoteJobsList();
|
||||
$scope.$on('$destroy', function() {
|
||||
websocketMsgSrv.unsubscribeJobManager();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
websocketMsgSrv.unsubscribeJobManager();
|
||||
});
|
||||
};
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('setNoteJobs', function(event, responseData) {
|
||||
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
|
||||
$scope.jobInfomations = responseData.jobs;
|
||||
$scope.jobInfomationsIndexs = $scope.jobInfomations ? _.indexBy($scope.jobInfomations, 'noteId') : {};
|
||||
$scope.jobTypeFilter($scope.jobInfomations, $scope.filterConfig);
|
||||
$scope.activeInterpreters = [
|
||||
{
|
||||
name: 'ALL',
|
||||
value: '*'
|
||||
}
|
||||
];
|
||||
var interpreterLists = _.uniq(_.pluck($scope.jobInfomations, 'interpreter'), false);
|
||||
for (var index = 0, length = interpreterLists.length; index < length; index++) {
|
||||
$scope.activeInterpreters.push({
|
||||
name: interpreterLists[index],
|
||||
value: interpreterLists[index]
|
||||
});
|
||||
$scope.$on('setNoteJobs', function(event, responseData) {
|
||||
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
|
||||
$scope.jobInfomations = responseData.jobs;
|
||||
$scope.jobInfomationsIndexs = $scope.jobInfomations ? _.indexBy($scope.jobInfomations, 'noteId') : {};
|
||||
$scope.jobTypeFilter($scope.jobInfomations, $scope.filterConfig);
|
||||
$scope.activeInterpreters = [
|
||||
{
|
||||
name: 'ALL',
|
||||
value: '*'
|
||||
}
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
});
|
||||
|
||||
$scope.$on('setUpdateNoteJobs', function(event, responseData) {
|
||||
var jobInfomations = $scope.jobInfomations;
|
||||
var indexStore = $scope.jobInfomationsIndexs;
|
||||
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
|
||||
var notes = responseData.jobs;
|
||||
notes.map(function(changedItem) {
|
||||
if (indexStore[changedItem.noteId] === undefined) {
|
||||
var newItem = angular.copy(changedItem);
|
||||
jobInfomations.push(newItem);
|
||||
indexStore[changedItem.noteId] = newItem;
|
||||
} else {
|
||||
var changeOriginTarget = indexStore[changedItem.noteId];
|
||||
|
||||
if (changedItem.isRemoved !== undefined && changedItem.isRemoved === true) {
|
||||
|
||||
// remove Item.
|
||||
var removeIndex = _.findIndex(indexStore, changedItem.noteId);
|
||||
if (removeIndex > -1) {
|
||||
indexStore.splice(removeIndex, 1);
|
||||
}
|
||||
|
||||
removeIndex = _.findIndex(jobInfomations, {'noteId': changedItem.noteId});
|
||||
if (removeIndex) {
|
||||
jobInfomations.splice(removeIndex, 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
// change value for item.
|
||||
changeOriginTarget.isRunningJob = changedItem.isRunningJob;
|
||||
changeOriginTarget.noteName = changedItem.noteName;
|
||||
changeOriginTarget.noteType = changedItem.noteType;
|
||||
changeOriginTarget.interpreter = changedItem.interpreter;
|
||||
changeOriginTarget.unixTimeLastRun = changedItem.unixTimeLastRun;
|
||||
changeOriginTarget.paragraphs = changedItem.paragraphs;
|
||||
}
|
||||
}
|
||||
];
|
||||
var interpreterLists = _.uniq(_.pluck($scope.jobInfomations, 'interpreter'), false);
|
||||
for (var index = 0, length = interpreterLists.length; index < length; index++) {
|
||||
$scope.activeInterpreters.push({
|
||||
name: interpreterLists[index],
|
||||
value: interpreterLists[index]
|
||||
});
|
||||
$scope.doFiltering(jobInfomations, $scope.filterConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
$scope.doFiltering($scope.jobInfomations, $scope.filterConfig);
|
||||
});
|
||||
|
||||
$scope.$on('setUpdateNoteJobs', function(event, responseData) {
|
||||
var jobInfomations = $scope.jobInfomations;
|
||||
var indexStore = $scope.jobInfomationsIndexs;
|
||||
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
|
||||
var notes = responseData.jobs;
|
||||
notes.map(function(changedItem) {
|
||||
if (indexStore[changedItem.noteId] === undefined) {
|
||||
var newItem = angular.copy(changedItem);
|
||||
jobInfomations.push(newItem);
|
||||
indexStore[changedItem.noteId] = newItem;
|
||||
} else {
|
||||
var changeOriginTarget = indexStore[changedItem.noteId];
|
||||
|
||||
if (changedItem.isRemoved !== undefined && changedItem.isRemoved === true) {
|
||||
|
||||
// remove Item.
|
||||
var removeIndex = _.findIndex(indexStore, changedItem.noteId);
|
||||
if (removeIndex > -1) {
|
||||
indexStore.splice(removeIndex, 1);
|
||||
}
|
||||
|
||||
removeIndex = _.findIndex(jobInfomations, {'noteId': changedItem.noteId});
|
||||
if (removeIndex) {
|
||||
jobInfomations.splice(removeIndex, 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
// change value for item.
|
||||
changeOriginTarget.isRunningJob = changedItem.isRunningJob;
|
||||
changeOriginTarget.noteName = changedItem.noteName;
|
||||
changeOriginTarget.noteType = changedItem.noteType;
|
||||
changeOriginTarget.interpreter = changedItem.interpreter;
|
||||
changeOriginTarget.unixTimeLastRun = changedItem.unixTimeLastRun;
|
||||
changeOriginTarget.paragraphs = changedItem.paragraphs;
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.doFiltering(jobInfomations, $scope.filterConfig);
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,35 +11,33 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').filter('jobManager', jobManagerFilter);
|
||||
angular.module('zeppelinWebApp').filter('jobManager', jobManagerFilter);
|
||||
|
||||
function jobManagerFilter() {
|
||||
function filterContext(jobItems, filterConfig) {
|
||||
var filterValueInterpreter = filterConfig.filterValueInterpreter;
|
||||
var filterValueNotebookName = filterConfig.filterValueNotebookName;
|
||||
var filterItems = jobItems;
|
||||
function jobManagerFilter() {
|
||||
function filterContext(jobItems, filterConfig) {
|
||||
var filterValueInterpreter = filterConfig.filterValueInterpreter;
|
||||
var filterValueNotebookName = filterConfig.filterValueNotebookName;
|
||||
var filterItems = jobItems;
|
||||
|
||||
if (filterValueInterpreter === undefined) {
|
||||
filterItems = _.filter(filterItems, function(jobItem) {
|
||||
return jobItem.interpreter === undefined ? true : false;
|
||||
});
|
||||
} else if (filterValueInterpreter !== '*') {
|
||||
filterItems = _.where(filterItems, {interpreter: filterValueInterpreter});
|
||||
}
|
||||
|
||||
if (filterValueNotebookName !== '') {
|
||||
filterItems = _.filter(filterItems, function(jobItem) {
|
||||
var lowerFilterValue = filterValueNotebookName.toLocaleLowerCase();
|
||||
var lowerNotebookName = jobItem.noteName.toLocaleLowerCase();
|
||||
return lowerNotebookName.match(new RegExp('.*' + lowerFilterValue + '.*'));
|
||||
});
|
||||
}
|
||||
|
||||
return filterItems;
|
||||
if (filterValueInterpreter === undefined) {
|
||||
filterItems = _.filter(filterItems, function(jobItem) {
|
||||
return jobItem.interpreter === undefined ? true : false;
|
||||
});
|
||||
} else if (filterValueInterpreter !== '*') {
|
||||
filterItems = _.where(filterItems, {interpreter: filterValueInterpreter});
|
||||
}
|
||||
return filterContext;
|
||||
}
|
||||
|
||||
})();
|
||||
if (filterValueNotebookName !== '') {
|
||||
filterItems = _.filter(filterItems, function(jobItem) {
|
||||
var lowerFilterValue = filterValueNotebookName.toLocaleLowerCase();
|
||||
var lowerNotebookName = jobItem.noteName.toLocaleLowerCase();
|
||||
return lowerNotebookName.match(new RegExp('.*' + lowerFilterValue + '.*'));
|
||||
});
|
||||
}
|
||||
|
||||
return filterItems;
|
||||
}
|
||||
return filterContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,99 +11,97 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('JobCtrl', JobCtrl);
|
||||
angular.module('zeppelinWebApp').controller('JobCtrl', JobCtrl);
|
||||
|
||||
JobCtrl.$inject = ['$scope', '$http', 'baseUrlSrv'];
|
||||
JobCtrl.$inject = ['$scope', '$http', 'baseUrlSrv'];
|
||||
|
||||
function JobCtrl($scope, $http, baseUrlSrv) {
|
||||
$scope.init = function(jobInformation) {
|
||||
$scope.progressValue = 0;
|
||||
};
|
||||
function JobCtrl($scope, $http, baseUrlSrv) {
|
||||
$scope.init = function(jobInformation) {
|
||||
$scope.progressValue = 0;
|
||||
};
|
||||
|
||||
$scope.getProgress = function() {
|
||||
var statusList = _.pluck($scope.notebookJob.paragraphs, 'status');
|
||||
var runningJob = _.countBy(statusList, function(status) {
|
||||
if (status === 'FINISHED' || status === 'RUNNING') {
|
||||
return 'matchCount';
|
||||
} else {
|
||||
return 'none';
|
||||
}
|
||||
});
|
||||
var totalCount = statusList.length;
|
||||
var runningJobCount = runningJob.matchCount;
|
||||
var result = Math.ceil(runningJobCount / totalCount * 100);
|
||||
return isNaN(result) ? 0 : result;
|
||||
};
|
||||
$scope.getProgress = function() {
|
||||
var statusList = _.pluck($scope.notebookJob.paragraphs, 'status');
|
||||
var runningJob = _.countBy(statusList, function(status) {
|
||||
if (status === 'FINISHED' || status === 'RUNNING') {
|
||||
return 'matchCount';
|
||||
} else {
|
||||
return 'none';
|
||||
}
|
||||
});
|
||||
var totalCount = statusList.length;
|
||||
var runningJobCount = runningJob.matchCount;
|
||||
var result = Math.ceil(runningJobCount / totalCount * 100);
|
||||
return isNaN(result) ? 0 : result;
|
||||
};
|
||||
|
||||
$scope.runNotebookJob = function(notebookId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Run all paragraphs?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}).then(function successCallback(response) {
|
||||
// success
|
||||
}, function errorCallback(errorResponse) {
|
||||
var errorText = 'SERVER ERROR';
|
||||
if (!!errorResponse.data.message) {
|
||||
errorText = errorResponse.data.message;
|
||||
}
|
||||
BootstrapDialog.alert({
|
||||
closable: true,
|
||||
title: 'Execution Failure',
|
||||
message: errorText
|
||||
});
|
||||
$scope.runNotebookJob = function(notebookId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Run all paragraphs?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}).then(function successCallback(response) {
|
||||
// success
|
||||
}, function errorCallback(errorResponse) {
|
||||
var errorText = 'SERVER ERROR';
|
||||
if (!!errorResponse.data.message) {
|
||||
errorText = errorResponse.data.message;
|
||||
}
|
||||
BootstrapDialog.alert({
|
||||
closable: true,
|
||||
title: 'Execution Failure',
|
||||
message: errorText
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.stopNotebookJob = function(notebookId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Stop all paragraphs?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http({
|
||||
method: 'DELETE',
|
||||
url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}).then(function successCallback(response) {
|
||||
// success
|
||||
}, function errorCallback(errorResponse) {
|
||||
var errorText = 'SERVER ERROR';
|
||||
if (!!errorResponse.data.message) {
|
||||
$scope.stopNotebookJob = function(notebookId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Stop all paragraphs?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
$http({
|
||||
method: 'DELETE',
|
||||
url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}).then(function successCallback(response) {
|
||||
// success
|
||||
}, function errorCallback(errorResponse) {
|
||||
var errorText = 'SERVER ERROR';
|
||||
if (!!errorResponse.data.message) {
|
||||
|
||||
errorText = errorResponse.data.message;
|
||||
}
|
||||
BootstrapDialog.alert({
|
||||
closable: true,
|
||||
title: 'Stop Failure',
|
||||
message: errorText
|
||||
});
|
||||
errorText = errorResponse.data.message;
|
||||
}
|
||||
BootstrapDialog.alert({
|
||||
closable: true,
|
||||
title: 'Stop Failure',
|
||||
message: errorText
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.lastExecuteTime = function(unixtime) {
|
||||
return moment.unix(unixtime / 1000).fromNow();
|
||||
};
|
||||
$scope.lastExecuteTime = function(unixtime) {
|
||||
return moment.unix(unixtime / 1000).fromNow();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ limitations under the License.
|
|||
<span class="labelBtn btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-click="runNote()"
|
||||
ng-click="runAllParagraphs(note.id)"
|
||||
ng-class="{'disabled':isNoteRunning()}"
|
||||
tooltip-placement="bottom" tooltip="Run all paragraphs"
|
||||
ng-disabled="revisionView">
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,7 +13,7 @@ limitations under the License.
|
|||
-->
|
||||
|
||||
<div id="{{paragraph.id}}_runControl" class="runControl">
|
||||
<div id="{{paragraph.id}}_progress" class="progress" ng-show="paragraph.status=='RUNNING'">
|
||||
<div id="{{paragraph.id}}_progress" class="progress" ng-if="paragraph.status=='RUNNING'">
|
||||
<div ng-if="getProgress()>0 && getProgress()<100 && paragraph.status=='RUNNING'"
|
||||
class="progress-bar" role="progressbar" style="width:{{getProgress()}}%;"></div>
|
||||
<div ng-if="(getProgress()<=0 || getProgress()>=100) && (paragraph.status=='RUNNING' )"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -72,6 +72,10 @@ table.dataTable.table-condensed .sorting_desc:after {
|
|||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.plainTextContent{
|
||||
white-space:pre-wrap; /** to preserve white-space and newlines of result */
|
||||
}
|
||||
|
||||
.graphContainer {
|
||||
position: relative;
|
||||
margin-bottom: 5px;
|
||||
|
|
|
|||
|
|
@ -56,8 +56,7 @@ limitations under the License.
|
|||
ng-controller="ResultCtrl"
|
||||
ng-repeat="result in paragraph.results.msg track by $index"
|
||||
ng-init="init(result, paragraph.config.results[$index], paragraph, $index)"
|
||||
ng-include src="'app/notebook/paragraph/result/result.html'"
|
||||
>
|
||||
ng-include src="'app/notebook/paragraph/result/result.html'">
|
||||
</div>
|
||||
<div id="{{paragraph.id}}_error"
|
||||
class="error text"
|
||||
|
|
|
|||
|
|
@ -14,30 +14,32 @@ limitations under the License.
|
|||
|
||||
<div id="{{id}}_switch"
|
||||
ng-if="(type == 'TABLE' || apps.length > 0 || suggestion.available && suggestion.available.length > 0) && !asIframe && !viewOnly"
|
||||
class="btn-group"
|
||||
style="margin-bottom: 10px;">
|
||||
class="chart-selector">
|
||||
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-if="type == 'TABLE'"
|
||||
ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
ng-class="{'active' : viz.id == graphMode && !config.helium.activeApp}"
|
||||
ng-click="switchViz(viz.id)"><i ng-class="viz.icon"></i>
|
||||
</button>
|
||||
<div ng-if="type == 'TABLE'" class="btn-group">
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
ng-class="{'active' : viz.id == graphMode && !config.helium.activeApp}"
|
||||
ng-click="switchViz(viz.id)"><i ng-class="viz.icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
ng-if="type != 'TABLE'"
|
||||
ng-click="switchApp()"
|
||||
ng-class="{'active' : !config.helium.activeApp}"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-terminal"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button type="button"
|
||||
ng-if="type != 'TABLE'"
|
||||
ng-click="switchApp()"
|
||||
ng-class="{'active' : !config.helium.activeApp}"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-terminal"></i>
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-default btn-sm"
|
||||
ng-repeat="app in apps"
|
||||
ng-click="switchApp(app.id)"
|
||||
ng-class="{'active' : app.id == config.helium.activeApp}"
|
||||
ng-bind-html="app.pkg.icon">
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-sm"
|
||||
ng-repeat="app in apps"
|
||||
ng-click="switchApp(app.id)"
|
||||
ng-class="{'active' : app.id == config.helium.activeApp}"
|
||||
ng-bind-html="app.pkg.icon">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="{{paragraph.id}}_helium"
|
||||
|
|
@ -46,7 +48,6 @@ limitations under the License.
|
|||
style="margin-bottom: 10px;">
|
||||
<button type="button"
|
||||
class="btn btn-default btn-sm dropdown-toggle"
|
||||
ng-if="suggestion.available && suggestion.available.length > 0"
|
||||
data-toggle="dropdown"
|
||||
style="font-weight:bold; background-color:#ffdf96; border: 1px solid #FED233">
|
||||
He
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
<!--
|
||||
Licensed 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.
|
||||
-->
|
||||
<div
|
||||
id="p{{id}}_resize"
|
||||
ng-if="!config.helium.activeApp"
|
||||
style="padding-bottom: 5px;"
|
||||
resize='{"allowresize": "{{!asIframe && !viewOnly}}", "graphType": "{{type}}"}'
|
||||
resizable on-resize="resize(width, height);">
|
||||
<div ng-include src="'app/notebook/paragraph/result/result-graph.html'"></div>
|
||||
|
||||
<div id="{{id}}_comment"
|
||||
class="text"
|
||||
ng-if="type == 'TABLE' && tableDataComment"
|
||||
ng-bind-html="tableDataComment">
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_text"
|
||||
ng-if="type == 'TEXT'">
|
||||
<div class="fa fa-level-down scroll-paragraph-down"
|
||||
ng-show="showScrollDownIcon(id)"
|
||||
ng-click="scrollParagraphDown(id)"
|
||||
tooltip="Follow Output"></div>
|
||||
<div id="p{{id}}_text"
|
||||
style="max-height: {{config.graph.height}}px; overflow: auto"
|
||||
class="text"></div>
|
||||
<div class="fa fa-chevron-up scroll-paragraph-up"
|
||||
ng-show="showScrollUpIcon(id)"
|
||||
ng-click="scrollParagraphUp(id)"
|
||||
tooltip="Scroll Top"></div>
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_html"
|
||||
class="resultContained"
|
||||
ng-if="type == 'HTML'">
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_angular"
|
||||
class="resultContained"
|
||||
ng-if="type == 'ANGULAR'">
|
||||
</div>
|
||||
|
||||
<img id="{{id}}_img"
|
||||
ng-if="type == 'IMG'"
|
||||
ng-src="{{getBase64ImageSrc(result.data)}}" />
|
||||
</div>
|
||||
|
||||
<div ng-repeat="app in apps">
|
||||
<div id="p{{app.id}}"
|
||||
ng-show="config.helium.activeApp == app.id">
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load diff
20
zeppelin-web/src/app/notebook/paragraph/result/result.css
Normal file
20
zeppelin-web/src/app/notebook/paragraph/result/result.css
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
.chart-selector {
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
@ -21,38 +21,38 @@ limitations under the License.
|
|||
resize='{"allowresize": "{{!asIframe && !viewOnly}}", "graphType": "{{type}}"}'
|
||||
resizable on-resize="resize(width, height);">
|
||||
|
||||
<!-- graph setting -->
|
||||
<div class="option lightBold" style="overflow: visible;"
|
||||
ng-show="type=='TABLE' && graphMode!='table'
|
||||
&& config.graph.optionOpen && !asIframe && !viewOnly">
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="trsetting{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id"></div>
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="vizsetting{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id"></div>
|
||||
</div>
|
||||
<div ng-if="type=='TABLE'">
|
||||
<!-- graph setting -->
|
||||
<div class="option lightBold" style="overflow: visible;"
|
||||
ng-if="graphMode!='table'
|
||||
&& config.graph.optionOpen && !asIframe && !viewOnly">
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="trsetting{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id"></div>
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="vizsetting{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id"></div>
|
||||
</div>
|
||||
|
||||
<!-- graph -->
|
||||
<div id="p{{id}}_graph"
|
||||
class="graphContainer"
|
||||
ng-class="{'noOverflow': graphMode=='table'}"
|
||||
ng-show="type =='TABLE'"
|
||||
>
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="p{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id">
|
||||
<!-- graph -->
|
||||
<div id="p{{id}}_graph"
|
||||
class="graphContainer"
|
||||
ng-class="{'noOverflow': graphMode=='table'}"
|
||||
>
|
||||
<div ng-repeat="viz in builtInTableDataVisualizationList track by $index"
|
||||
id="p{{id}}_{{viz.id}}"
|
||||
ng-show="graphMode == viz.id">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="{{id}}_comment"
|
||||
class="text"
|
||||
ng-if="tableDataComment"
|
||||
ng-bind-html="tableDataComment">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="{{id}}_comment"
|
||||
class="text"
|
||||
ng-if="type == 'TABLE' && tableDataComment"
|
||||
ng-bind-html="tableDataComment">
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_text"
|
||||
ng-if="type == 'TEXT'"
|
||||
<div ng-if="type == 'TEXT'"
|
||||
class="plainTextContainer">
|
||||
<div class="fa fa-level-down scroll-paragraph-down"
|
||||
ng-show="showScrollDownIcon()"
|
||||
|
|
@ -60,7 +60,7 @@ limitations under the License.
|
|||
tooltip="Follow Output"></div>
|
||||
<div id="p{{id}}_text"
|
||||
style="max-height: {{config.graph.height}}px; overflow: auto"
|
||||
class="text"></div>
|
||||
class="text plainTextContent"></div>
|
||||
<div class="fa fa-chevron-up scroll-paragraph-up"
|
||||
ng-show="showScrollUpIcon()"
|
||||
ng-click="scrollParagraphUp()"
|
||||
|
|
|
|||
|
|
@ -11,80 +11,78 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NotebookReposCtrl', NotebookReposCtrl);
|
||||
angular.module('zeppelinWebApp').controller('NotebookReposCtrl', NotebookReposCtrl);
|
||||
|
||||
NotebookReposCtrl.$inject = ['$http', 'baseUrlSrv', 'ngToast'];
|
||||
NotebookReposCtrl.$inject = ['$http', 'baseUrlSrv', 'ngToast'];
|
||||
|
||||
function NotebookReposCtrl($http, baseUrlSrv, ngToast) {
|
||||
var vm = this;
|
||||
vm.notebookRepos = [];
|
||||
vm.showDropdownSelected = showDropdownSelected;
|
||||
vm.saveNotebookRepo = saveNotebookRepo;
|
||||
function NotebookReposCtrl($http, baseUrlSrv, ngToast) {
|
||||
var vm = this;
|
||||
vm.notebookRepos = [];
|
||||
vm.showDropdownSelected = showDropdownSelected;
|
||||
vm.saveNotebookRepo = saveNotebookRepo;
|
||||
|
||||
_init();
|
||||
_init();
|
||||
|
||||
// Public functions
|
||||
// Public functions
|
||||
|
||||
function saveNotebookRepo(valueform, repo, data) {
|
||||
console.log('data %o', data);
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/notebook-repositories', {
|
||||
'name': repo.className,
|
||||
'settings': data
|
||||
}).success(function(data) {
|
||||
var index = _.findIndex(vm.notebookRepos, {'className': repo.className});
|
||||
if (index >= 0) {
|
||||
vm.notebookRepos[index] = data.body;
|
||||
console.log('repos %o, data %o', vm.notebookRepos, data.body);
|
||||
}
|
||||
valueform.$show();
|
||||
}).error(function() {
|
||||
ngToast.danger({
|
||||
content: 'We couldn\'t save that NotebookRepo\'s settings',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
valueform.$show();
|
||||
});
|
||||
|
||||
return 'manual';
|
||||
}
|
||||
|
||||
function showDropdownSelected(setting) {
|
||||
var index = _.findIndex(setting.value, {'value': setting.selected});
|
||||
if (index < 0) {
|
||||
return 'No value';
|
||||
} else {
|
||||
return setting.value[index].name;
|
||||
function saveNotebookRepo(valueform, repo, data) {
|
||||
console.log('data %o', data);
|
||||
$http.put(baseUrlSrv.getRestApiBase() + '/notebook-repositories', {
|
||||
'name': repo.className,
|
||||
'settings': data
|
||||
}).success(function(data) {
|
||||
var index = _.findIndex(vm.notebookRepos, {'className': repo.className});
|
||||
if (index >= 0) {
|
||||
vm.notebookRepos[index] = data.body;
|
||||
console.log('repos %o, data %o', vm.notebookRepos, data.body);
|
||||
}
|
||||
valueform.$show();
|
||||
}).error(function() {
|
||||
ngToast.danger({
|
||||
content: 'We couldn\'t save that NotebookRepo\'s settings',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
valueform.$show();
|
||||
});
|
||||
|
||||
return 'manual';
|
||||
}
|
||||
|
||||
function showDropdownSelected(setting) {
|
||||
var index = _.findIndex(setting.value, {'value': setting.selected});
|
||||
if (index < 0) {
|
||||
return 'No value';
|
||||
} else {
|
||||
return setting.value[index].name;
|
||||
}
|
||||
}
|
||||
|
||||
// Private functions
|
||||
// Private functions
|
||||
|
||||
function _getInterpreterSettings() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/notebook-repositories')
|
||||
function _getInterpreterSettings() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/notebook-repositories')
|
||||
.success(function(data, status, headers, config) {
|
||||
vm.notebookRepos = data.body;
|
||||
console.log('ya notebookRepos %o', vm.notebookRepos);
|
||||
}).error(function(data, status, headers, config) {
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
}
|
||||
|
||||
function _init() {
|
||||
_getInterpreterSettings();
|
||||
};
|
||||
if (status === 401) {
|
||||
ngToast.danger({
|
||||
content: 'You don\'t have permission on this page',
|
||||
verticalPosition: 'bottom',
|
||||
timeout: '3000'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 3000);
|
||||
}
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
function _init() {
|
||||
_getInterpreterSettings();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,148 +11,146 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('SearchResultCtrl', SearchResultCtrl);
|
||||
angular.module('zeppelinWebApp').controller('SearchResultCtrl', SearchResultCtrl);
|
||||
|
||||
SearchResultCtrl.$inject = ['$scope', '$routeParams', 'searchService'];
|
||||
SearchResultCtrl.$inject = ['$scope', '$routeParams', 'searchService'];
|
||||
|
||||
function SearchResultCtrl($scope, $routeParams, searchService) {
|
||||
$scope.isResult = true ;
|
||||
$scope.searchTerm = $routeParams.searchTerm;
|
||||
var results = searchService.search({'q': $routeParams.searchTerm}).query();
|
||||
|
||||
results.$promise.then(function(result) {
|
||||
$scope.notes = result.body.map(function(note) {
|
||||
// redirect to notebook when search result is a notebook itself,
|
||||
// not a paragraph
|
||||
if (!/\/paragraph\//.test(note.id)) {
|
||||
return note;
|
||||
}
|
||||
|
||||
note.id = note.id.replace('paragraph/', '?paragraph=') +
|
||||
'&term=' + $routeParams.searchTerm;
|
||||
function SearchResultCtrl($scope, $routeParams, searchService) {
|
||||
$scope.isResult = true ;
|
||||
$scope.searchTerm = $routeParams.searchTerm;
|
||||
var results = searchService.search({'q': $routeParams.searchTerm}).query();
|
||||
|
||||
results.$promise.then(function(result) {
|
||||
$scope.notes = result.body.map(function(note) {
|
||||
// redirect to notebook when search result is a notebook itself,
|
||||
// not a paragraph
|
||||
if (!/\/paragraph\//.test(note.id)) {
|
||||
return note;
|
||||
});
|
||||
if ($scope.notes.length === 0) {
|
||||
$scope.isResult = false;
|
||||
} else {
|
||||
$scope.isResult = true;
|
||||
}
|
||||
|
||||
$scope.$on('$routeChangeStart', function(event, next, current) {
|
||||
if (next.originalPath !== '/search/:searchTerm') {
|
||||
searchService.searchTerm = '';
|
||||
}
|
||||
});
|
||||
note.id = note.id.replace('paragraph/', '?paragraph=') +
|
||||
'&term=' + $routeParams.searchTerm;
|
||||
|
||||
return note;
|
||||
});
|
||||
if ($scope.notes.length === 0) {
|
||||
$scope.isResult = false;
|
||||
} else {
|
||||
$scope.isResult = true;
|
||||
}
|
||||
|
||||
$scope.page = 0;
|
||||
$scope.allResults = false;
|
||||
$scope.$on('$routeChangeStart', function(event, next, current) {
|
||||
if (next.originalPath !== '/search/:searchTerm') {
|
||||
searchService.searchTerm = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.highlightSearchResults = function(note) {
|
||||
return function(_editor) {
|
||||
function getEditorMode(text) {
|
||||
var editorModes = {
|
||||
'ace/mode/scala': /^%(\w*\.)?spark/,
|
||||
'ace/mode/python': /^%(\w*\.)?(pyspark|python)/,
|
||||
'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)/,
|
||||
'ace/mode/sql': /^%(\w*\.)?\wql/,
|
||||
'ace/mode/markdown': /^%md/,
|
||||
'ace/mode/sh': /^%sh/
|
||||
};
|
||||
$scope.page = 0;
|
||||
$scope.allResults = false;
|
||||
|
||||
return Object.keys(editorModes).reduce(function(res, mode) {
|
||||
return editorModes[mode].test(text) ? mode : res;
|
||||
}, 'ace/mode/scala');
|
||||
}
|
||||
$scope.highlightSearchResults = function(note) {
|
||||
return function(_editor) {
|
||||
function getEditorMode(text) {
|
||||
var editorModes = {
|
||||
'ace/mode/scala': /^%(\w*\.)?spark/,
|
||||
'ace/mode/python': /^%(\w*\.)?(pyspark|python)/,
|
||||
'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)/,
|
||||
'ace/mode/sql': /^%(\w*\.)?\wql/,
|
||||
'ace/mode/markdown': /^%md/,
|
||||
'ace/mode/sh': /^%sh/
|
||||
};
|
||||
|
||||
var Range = ace.require('ace/range').Range;
|
||||
return Object.keys(editorModes).reduce(function(res, mode) {
|
||||
return editorModes[mode].test(text) ? mode : res;
|
||||
}, 'ace/mode/scala');
|
||||
}
|
||||
|
||||
_editor.setOption('highlightActiveLine', false);
|
||||
_editor.$blockScrolling = Infinity;
|
||||
_editor.setReadOnly(true);
|
||||
_editor.renderer.setShowGutter(false);
|
||||
_editor.setTheme('ace/theme/chrome');
|
||||
_editor.getSession().setMode(getEditorMode(note.text));
|
||||
var Range = ace.require('ace/range').Range;
|
||||
|
||||
function getIndeces(term) {
|
||||
return function(str) {
|
||||
var indeces = [];
|
||||
var i = -1;
|
||||
while ((i = str.indexOf(term, i + 1)) >= 0) {
|
||||
indeces.push(i);
|
||||
_editor.setOption('highlightActiveLine', false);
|
||||
_editor.$blockScrolling = Infinity;
|
||||
_editor.setReadOnly(true);
|
||||
_editor.renderer.setShowGutter(false);
|
||||
_editor.setTheme('ace/theme/chrome');
|
||||
_editor.getSession().setMode(getEditorMode(note.text));
|
||||
|
||||
function getIndeces(term) {
|
||||
return function(str) {
|
||||
var indeces = [];
|
||||
var i = -1;
|
||||
while ((i = str.indexOf(term, i + 1)) >= 0) {
|
||||
indeces.push(i);
|
||||
}
|
||||
return indeces;
|
||||
};
|
||||
}
|
||||
|
||||
var result = '';
|
||||
if (note.header !== '') {
|
||||
result = note.header + '\n\n' + note.snippet;
|
||||
} else {
|
||||
result = note.snippet;
|
||||
}
|
||||
|
||||
var lines = result
|
||||
.split('\n')
|
||||
.map(function(line, row) {
|
||||
|
||||
var match = line.match(/<B>(.+?)<\/B>/);
|
||||
|
||||
// return early if nothing to highlight
|
||||
if (!match) {
|
||||
return line;
|
||||
}
|
||||
|
||||
var term = match[1];
|
||||
var __line = line
|
||||
.replace(/<B>/g, '')
|
||||
.replace(/<\/B>/g, '');
|
||||
|
||||
var indeces = getIndeces(term)(__line);
|
||||
|
||||
indeces.forEach(function(start) {
|
||||
var end = start + term.length;
|
||||
if (note.header !== '' && row === 0) {
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, 0, row, line.length),
|
||||
'search-results-highlight-header',
|
||||
'background'
|
||||
);
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, start, row, end),
|
||||
'search-results-highlight',
|
||||
'line'
|
||||
);
|
||||
} else {
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, start, row, end),
|
||||
'search-results-highlight',
|
||||
'line'
|
||||
);
|
||||
}
|
||||
return indeces;
|
||||
};
|
||||
}
|
||||
|
||||
var result = '';
|
||||
if (note.header !== '') {
|
||||
result = note.header + '\n\n' + note.snippet;
|
||||
} else {
|
||||
result = note.snippet;
|
||||
}
|
||||
|
||||
var lines = result
|
||||
.split('\n')
|
||||
.map(function(line, row) {
|
||||
|
||||
var match = line.match(/<B>(.+?)<\/B>/);
|
||||
|
||||
// return early if nothing to highlight
|
||||
if (!match) {
|
||||
return line;
|
||||
}
|
||||
|
||||
var term = match[1];
|
||||
var __line = line
|
||||
.replace(/<B>/g, '')
|
||||
.replace(/<\/B>/g, '');
|
||||
|
||||
var indeces = getIndeces(term)(__line);
|
||||
|
||||
indeces.forEach(function(start) {
|
||||
var end = start + term.length;
|
||||
if (note.header !== '' && row === 0) {
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, 0, row, line.length),
|
||||
'search-results-highlight-header',
|
||||
'background'
|
||||
);
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, start, row, end),
|
||||
'search-results-highlight',
|
||||
'line'
|
||||
);
|
||||
} else {
|
||||
_editor
|
||||
.getSession()
|
||||
.addMarker(
|
||||
new Range(row, start, row, end),
|
||||
'search-results-highlight',
|
||||
'line'
|
||||
);
|
||||
}
|
||||
});
|
||||
return __line;
|
||||
});
|
||||
return __line;
|
||||
});
|
||||
|
||||
// resize editor based on content length
|
||||
_editor.setOption(
|
||||
'maxLines',
|
||||
lines.reduce(function(len, line) {return len + line.length;}, 0)
|
||||
);
|
||||
// resize editor based on content length
|
||||
_editor.setOption(
|
||||
'maxLines',
|
||||
lines.reduce(function(len, line) {return len + line.length;}, 0)
|
||||
);
|
||||
|
||||
_editor.getSession().setValue(lines.join('\n'));
|
||||
_editor.getSession().setValue(lines.join('\n'));
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,29 +11,27 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('arrayOrderingSrv', arrayOrderingSrv);
|
||||
angular.module('zeppelinWebApp').service('arrayOrderingSrv', arrayOrderingSrv);
|
||||
|
||||
arrayOrderingSrv.$inject = ['TRASH_FOLDER_ID'];
|
||||
arrayOrderingSrv.$inject = ['TRASH_FOLDER_ID'];
|
||||
|
||||
function arrayOrderingSrv(TRASH_FOLDER_ID) {
|
||||
var arrayOrderingSrv = this;
|
||||
function arrayOrderingSrv(TRASH_FOLDER_ID) {
|
||||
var arrayOrderingSrv = this;
|
||||
|
||||
this.noteListOrdering = function(note) {
|
||||
if (note.id === TRASH_FOLDER_ID) {
|
||||
return '\uFFFF';
|
||||
}
|
||||
return arrayOrderingSrv.getNoteName(note);
|
||||
};
|
||||
this.noteListOrdering = function(note) {
|
||||
if (note.id === TRASH_FOLDER_ID) {
|
||||
return '\uFFFF';
|
||||
}
|
||||
return arrayOrderingSrv.getNoteName(note);
|
||||
};
|
||||
|
||||
this.getNoteName = function(note) {
|
||||
if (note.name === undefined || note.name.trim() === '') {
|
||||
return 'Note ' + note.id;
|
||||
} else {
|
||||
return note.name;
|
||||
}
|
||||
};
|
||||
}
|
||||
this.getNoteName = function(note) {
|
||||
if (note.name === undefined || note.name.trim() === '') {
|
||||
return 'Note ' + note.id;
|
||||
} else {
|
||||
return note.name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,41 +11,39 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('baseUrlSrv', baseUrlSrv);
|
||||
angular.module('zeppelinWebApp').service('baseUrlSrv', baseUrlSrv);
|
||||
|
||||
function baseUrlSrv() {
|
||||
this.getPort = function() {
|
||||
var port = Number(location.port);
|
||||
if (!port) {
|
||||
port = 80;
|
||||
if (location.protocol === 'https:') {
|
||||
port = 443;
|
||||
}
|
||||
function baseUrlSrv() {
|
||||
this.getPort = function() {
|
||||
var port = Number(location.port);
|
||||
if (!port) {
|
||||
port = 80;
|
||||
if (location.protocol === 'https:') {
|
||||
port = 443;
|
||||
}
|
||||
//Exception for when running locally via grunt
|
||||
if (port === 3333 || port === 9000) {
|
||||
port = 8080;
|
||||
}
|
||||
return port;
|
||||
};
|
||||
}
|
||||
//Exception for when running locally via grunt
|
||||
if (port === 3333 || port === 9000) {
|
||||
port = 8080;
|
||||
}
|
||||
return port;
|
||||
};
|
||||
|
||||
this.getWebsocketUrl = function() {
|
||||
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
return wsProtocol + '//' + location.hostname + ':' + this.getPort() +
|
||||
this.getWebsocketUrl = function() {
|
||||
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
return wsProtocol + '//' + location.hostname + ':' + this.getPort() +
|
||||
skipTrailingSlash(location.pathname) + '/ws';
|
||||
};
|
||||
};
|
||||
|
||||
this.getRestApiBase = function() {
|
||||
return location.protocol + '//' + location.hostname + ':' +
|
||||
this.getRestApiBase = function() {
|
||||
return location.protocol + '//' + location.hostname + ':' +
|
||||
this.getPort() + skipTrailingSlash(location.pathname) +
|
||||
'/api';
|
||||
};
|
||||
'/api';
|
||||
};
|
||||
|
||||
var skipTrailingSlash = function(path) {
|
||||
return path.replace(/\/$/, '');
|
||||
};
|
||||
}
|
||||
var skipTrailingSlash = function(path) {
|
||||
return path.replace(/\/$/, '');
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,32 +11,30 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('browserDetectService', browserDetectService);
|
||||
angular.module('zeppelinWebApp').service('browserDetectService', browserDetectService);
|
||||
|
||||
function browserDetectService() {
|
||||
this.detectIE = function() {
|
||||
var ua = window.navigator.userAgent;
|
||||
var msie = ua.indexOf('MSIE ');
|
||||
if (msie > 0) {
|
||||
// IE 10 or older => return version number
|
||||
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
||||
}
|
||||
var trident = ua.indexOf('Trident/');
|
||||
if (trident > 0) {
|
||||
// IE 11 => return version number
|
||||
var rv = ua.indexOf('rv:');
|
||||
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
||||
}
|
||||
var edge = ua.indexOf('Edge/');
|
||||
if (edge > 0) {
|
||||
// IE 12 (aka Edge) => return version number
|
||||
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
||||
}
|
||||
// other browser
|
||||
return false;
|
||||
};
|
||||
}
|
||||
function browserDetectService() {
|
||||
this.detectIE = function() {
|
||||
var ua = window.navigator.userAgent;
|
||||
var msie = ua.indexOf('MSIE ');
|
||||
if (msie > 0) {
|
||||
// IE 10 or older => return version number
|
||||
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
||||
}
|
||||
var trident = ua.indexOf('Trident/');
|
||||
if (trident > 0) {
|
||||
// IE 11 => return version number
|
||||
var rv = ua.indexOf('rv:');
|
||||
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
||||
}
|
||||
var edge = ua.indexOf('Edge/');
|
||||
if (edge > 0) {
|
||||
// IE 12 (aka Edge) => return version number
|
||||
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
||||
}
|
||||
// other browser
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,25 +11,23 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
angular.module('zeppelinWebApp').controller('clipboardCtrl', clipboardCtrl);
|
||||
clipboardCtrl.$inject = ['$scope'];
|
||||
angular.module('zeppelinWebApp').controller('clipboardCtrl', clipboardCtrl);
|
||||
clipboardCtrl.$inject = ['$scope'];
|
||||
|
||||
function clipboardCtrl($scope) {
|
||||
$scope.complete = function(e) {
|
||||
$scope.copied = true;
|
||||
$scope.tooltip = 'Copied!';
|
||||
setTimeout(function() {
|
||||
$scope.tooltip = 'Copy to clipboard';
|
||||
}, 400);
|
||||
};
|
||||
$scope.$watch('input', function() {
|
||||
$scope.copied = false;
|
||||
function clipboardCtrl($scope) {
|
||||
$scope.complete = function(e) {
|
||||
$scope.copied = true;
|
||||
$scope.tooltip = 'Copied!';
|
||||
setTimeout(function() {
|
||||
$scope.tooltip = 'Copy to clipboard';
|
||||
});
|
||||
$scope.clipError = function(e) {
|
||||
console.log('Error: ' + e.name + ' - ' + e.message);
|
||||
$scope.tooltip = 'Not supported browser';
|
||||
};
|
||||
}
|
||||
})();
|
||||
}, 400);
|
||||
};
|
||||
$scope.$watch('input', function() {
|
||||
$scope.copied = false;
|
||||
$scope.tooltip = 'Copy to clipboard';
|
||||
});
|
||||
$scope.clipError = function(e) {
|
||||
console.log('Error: ' + e.name + ' - ' + e.message);
|
||||
$scope.tooltip = 'Not supported browser';
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,19 +11,17 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('dropdownInput', dropdownInput);
|
||||
angular.module('zeppelinWebApp').directive('dropdownInput', dropdownInput);
|
||||
|
||||
function dropdownInput() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element) {
|
||||
element.bind('click', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
function dropdownInput() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element) {
|
||||
element.bind('click', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,31 +11,29 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('codeEditor', codeEditor);
|
||||
angular.module('zeppelinWebApp').directive('codeEditor', codeEditor);
|
||||
|
||||
function codeEditor($templateRequest, $compile) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
scope: {
|
||||
paragraphId: '=paragraphId',
|
||||
paragraph: '=paragraphContext',
|
||||
dirtyText: '=dirtyText',
|
||||
originalText: '=originalText',
|
||||
onLoad: '=onLoad',
|
||||
revisionView: '=revisionView'
|
||||
},
|
||||
link: function(scope, element, attrs, controller) {
|
||||
$templateRequest('components/editor/ace.editor.directive.html').then(function(editorHtml) {
|
||||
var editor = angular.element(editorHtml);
|
||||
editor.attr('id', scope.paragraphId + '_editor');
|
||||
element.append(editor);
|
||||
$compile(editor)(scope);
|
||||
console.log('codeEditor directive revision view is ' + scope.revisionView);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
function codeEditor($templateRequest, $compile) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
scope: {
|
||||
paragraphId: '=paragraphId',
|
||||
paragraph: '=paragraphContext',
|
||||
dirtyText: '=dirtyText',
|
||||
originalText: '=originalText',
|
||||
onLoad: '=onLoad',
|
||||
revisionView: '=revisionView'
|
||||
},
|
||||
link: function(scope, element, attrs, controller) {
|
||||
$templateRequest('components/editor/ace.editor.directive.html').then(function(editorHtml) {
|
||||
var editor = angular.element(editorHtml);
|
||||
editor.attr('id', scope.paragraphId + '_editor');
|
||||
element.append(editor);
|
||||
$compile(editor)(scope);
|
||||
console.log('codeEditor directive revision view is ' + scope.revisionView);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,14 +11,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('ElasticInputCtrl', ElasticInputCtrl);
|
||||
angular.module('zeppelinWebApp').controller('ElasticInputCtrl', ElasticInputCtrl);
|
||||
|
||||
function ElasticInputCtrl() {
|
||||
var vm = this;
|
||||
vm.showEditor = false;
|
||||
vm.value = '';
|
||||
}
|
||||
function ElasticInputCtrl() {
|
||||
var vm = this;
|
||||
vm.showEditor = false;
|
||||
vm.value = '';
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,30 +11,28 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('expandCollapse', expandCollapse);
|
||||
angular.module('zeppelinWebApp').directive('expandCollapse', expandCollapse);
|
||||
|
||||
function expandCollapse() {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
link: function(scope, element, attrs) {
|
||||
angular.element(element).click(function(event) {
|
||||
if (angular.element(element).find('.expandable:visible').length > 1) {
|
||||
angular.element(element).find('.expandable:visible').slideUp('slow');
|
||||
angular.element(element).find('i.icon-folder-alt').toggleClass('icon-folder icon-folder-alt');
|
||||
} else {
|
||||
angular.element(element).find('.expandable').first().slideToggle('200',function() {
|
||||
// do not toggle trash folder
|
||||
if (angular.element(element).find('.fa-trash-o').length === 0) {
|
||||
angular.element(element).find('i').first().toggleClass('icon-folder icon-folder-alt');
|
||||
}
|
||||
});
|
||||
}
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
function expandCollapse() {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
link: function(scope, element, attrs) {
|
||||
angular.element(element).click(function(event) {
|
||||
if (angular.element(element).find('.expandable:visible').length > 1) {
|
||||
angular.element(element).find('.expandable:visible').slideUp('slow');
|
||||
angular.element(element).find('i.icon-folder-alt').toggleClass('icon-folder icon-folder-alt');
|
||||
} else {
|
||||
angular.element(element).find('.expandable').first().slideToggle('200',function() {
|
||||
// do not toggle trash folder
|
||||
if (angular.element(element).find('.fa-trash-o').length === 0) {
|
||||
angular.element(element).find('i').first().toggleClass('icon-folder icon-folder-alt');
|
||||
}
|
||||
});
|
||||
}
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,24 +11,22 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('interpreterDirective', interpreterDirective);
|
||||
angular.module('zeppelinWebApp').directive('interpreterDirective', interpreterDirective);
|
||||
|
||||
interpreterDirective.$inject = ['$timeout'];
|
||||
interpreterDirective.$inject = ['$timeout'];
|
||||
|
||||
function interpreterDirective($timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attr) {
|
||||
if (scope.$last === true) {
|
||||
$timeout(function() {
|
||||
var id = 'ngRenderFinished';
|
||||
scope.$emit(id);
|
||||
});
|
||||
}
|
||||
function interpreterDirective($timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attr) {
|
||||
if (scope.$last === true) {
|
||||
$timeout(function() {
|
||||
var id = 'ngRenderFinished';
|
||||
scope.$emit(id);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,53 +11,51 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('LoginCtrl', LoginCtrl);
|
||||
angular.module('zeppelinWebApp').controller('LoginCtrl', LoginCtrl);
|
||||
|
||||
LoginCtrl.$inject = ['$scope', '$rootScope', '$http', '$httpParamSerializer', 'baseUrlSrv'];
|
||||
function LoginCtrl($scope, $rootScope, $http, $httpParamSerializer, baseUrlSrv) {
|
||||
$scope.SigningIn = false;
|
||||
$scope.loginParams = {};
|
||||
$scope.login = function() {
|
||||
LoginCtrl.$inject = ['$scope', '$rootScope', '$http', '$httpParamSerializer', 'baseUrlSrv'];
|
||||
function LoginCtrl($scope, $rootScope, $http, $httpParamSerializer, baseUrlSrv) {
|
||||
$scope.SigningIn = false;
|
||||
$scope.loginParams = {};
|
||||
$scope.login = function() {
|
||||
|
||||
$scope.SigningIn = true;
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: baseUrlSrv.getRestApiBase() + '/login',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: $httpParamSerializer({
|
||||
'userName': $scope.loginParams.userName,
|
||||
'password': $scope.loginParams.password
|
||||
})
|
||||
}).then(function successCallback(response) {
|
||||
$rootScope.ticket = response.data.body;
|
||||
angular.element('#loginModal').modal('toggle');
|
||||
$rootScope.$broadcast('loginSuccess', true);
|
||||
$rootScope.userName = $scope.loginParams.userName;
|
||||
}, function errorCallback(errorResponse) {
|
||||
$scope.loginParams.errorText = 'The username and password that you entered don\'t match.';
|
||||
$scope.SigningIn = false;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var initValues = function() {
|
||||
$scope.loginParams = {
|
||||
userName: '',
|
||||
password: ''
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('initLoginValues', function() {
|
||||
initValues();
|
||||
$scope.SigningIn = true;
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: baseUrlSrv.getRestApiBase() + '/login',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: $httpParamSerializer({
|
||||
'userName': $scope.loginParams.userName,
|
||||
'password': $scope.loginParams.password
|
||||
})
|
||||
}).then(function successCallback(response) {
|
||||
$rootScope.ticket = response.data.body;
|
||||
angular.element('#loginModal').modal('toggle');
|
||||
$rootScope.$broadcast('loginSuccess', true);
|
||||
$rootScope.userName = $scope.loginParams.userName;
|
||||
}, function errorCallback(errorResponse) {
|
||||
$scope.loginParams.errorText = 'The username and password that you entered don\'t match.';
|
||||
$scope.SigningIn = false;
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
};
|
||||
|
||||
var initValues = function() {
|
||||
$scope.loginParams = {
|
||||
userName: '',
|
||||
password: ''
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('initLoginValues', function() {
|
||||
initValues();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,135 +11,133 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NavCtrl', NavCtrl);
|
||||
angular.module('zeppelinWebApp').controller('NavCtrl', NavCtrl);
|
||||
|
||||
NavCtrl.$inject = [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'$http',
|
||||
'$routeParams',
|
||||
'$location',
|
||||
'noteListDataFactory',
|
||||
'baseUrlSrv',
|
||||
'websocketMsgSrv',
|
||||
'arrayOrderingSrv',
|
||||
'searchService',
|
||||
'TRASH_FOLDER_ID'
|
||||
];
|
||||
NavCtrl.$inject = [
|
||||
'$scope',
|
||||
'$rootScope',
|
||||
'$http',
|
||||
'$routeParams',
|
||||
'$location',
|
||||
'noteListDataFactory',
|
||||
'baseUrlSrv',
|
||||
'websocketMsgSrv',
|
||||
'arrayOrderingSrv',
|
||||
'searchService',
|
||||
'TRASH_FOLDER_ID'
|
||||
];
|
||||
|
||||
function NavCtrl($scope, $rootScope, $http, $routeParams, $location,
|
||||
noteListDataFactory, baseUrlSrv, websocketMsgSrv,
|
||||
arrayOrderingSrv, searchService, TRASH_FOLDER_ID) {
|
||||
var vm = this;
|
||||
vm.arrayOrderingSrv = arrayOrderingSrv;
|
||||
vm.connected = websocketMsgSrv.isConnected();
|
||||
vm.isActive = isActive;
|
||||
vm.logout = logout;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.search = search;
|
||||
vm.searchForm = searchService;
|
||||
vm.showLoginWindow = showLoginWindow;
|
||||
vm.TRASH_FOLDER_ID = TRASH_FOLDER_ID;
|
||||
function NavCtrl($scope, $rootScope, $http, $routeParams, $location,
|
||||
noteListDataFactory, baseUrlSrv, websocketMsgSrv,
|
||||
arrayOrderingSrv, searchService, TRASH_FOLDER_ID) {
|
||||
var vm = this;
|
||||
vm.arrayOrderingSrv = arrayOrderingSrv;
|
||||
vm.connected = websocketMsgSrv.isConnected();
|
||||
vm.isActive = isActive;
|
||||
vm.logout = logout;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.search = search;
|
||||
vm.searchForm = searchService;
|
||||
vm.showLoginWindow = showLoginWindow;
|
||||
vm.TRASH_FOLDER_ID = TRASH_FOLDER_ID;
|
||||
|
||||
$scope.query = {q: ''};
|
||||
$scope.query = {q: ''};
|
||||
|
||||
initController();
|
||||
initController();
|
||||
|
||||
function getZeppelinVersion() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/version').success(
|
||||
function(data, status, headers, config) {
|
||||
$rootScope.zeppelinVersion = data.body;
|
||||
}).error(
|
||||
function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
}
|
||||
|
||||
function initController() {
|
||||
$scope.isDrawNavbarNoteList = false;
|
||||
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
|
||||
|
||||
angular.element(document).click(function() {
|
||||
$scope.query.q = '';
|
||||
function getZeppelinVersion() {
|
||||
$http.get(baseUrlSrv.getRestApiBase() + '/version').success(
|
||||
function(data, status, headers, config) {
|
||||
$rootScope.zeppelinVersion = data.body;
|
||||
}).error(
|
||||
function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
|
||||
getZeppelinVersion();
|
||||
loadNotes();
|
||||
}
|
||||
|
||||
function isActive(noteId) {
|
||||
return ($routeParams.noteId === noteId);
|
||||
}
|
||||
|
||||
function loadNotes() {
|
||||
websocketMsgSrv.getNoteList();
|
||||
}
|
||||
|
||||
function logout() {
|
||||
var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
|
||||
|
||||
//for firefox and safari
|
||||
logoutURL = logoutURL.replace('//', '//false:false@');
|
||||
$http.post(logoutURL).error(function() {
|
||||
//force authcBasic (if configured) to logout
|
||||
$http.post(logoutURL).error(function() {
|
||||
$rootScope.userName = '';
|
||||
$rootScope.ticket.principal = '';
|
||||
$rootScope.ticket.ticket = '';
|
||||
$rootScope.ticket.roles = '';
|
||||
BootstrapDialog.show({
|
||||
message: 'Logout Success'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function search(searchTerm) {
|
||||
$location.path('/search/' + searchTerm);
|
||||
}
|
||||
|
||||
function showLoginWindow() {
|
||||
setTimeout(function() {
|
||||
angular.element('#userName').focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
noteListDataFactory.setNotes(notes);
|
||||
initNotebookListEventListener();
|
||||
});
|
||||
|
||||
$scope.$on('setConnectedStatus', function(event, param) {
|
||||
vm.connected = param;
|
||||
});
|
||||
|
||||
$scope.$on('loginSuccess', function(event, param) {
|
||||
loadNotes();
|
||||
});
|
||||
|
||||
/*
|
||||
** Performance optimization for Browser Render.
|
||||
*/
|
||||
function initNotebookListEventListener() {
|
||||
angular.element(document).ready(function() {
|
||||
angular.element('.notebook-list-dropdown').on('show.bs.dropdown', function() {
|
||||
$scope.isDrawNavbarNoteList = true;
|
||||
});
|
||||
|
||||
angular.element('.notebook-list-dropdown').on('hide.bs.dropdown', function() {
|
||||
$scope.isDrawNavbarNoteList = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
function initController() {
|
||||
$scope.isDrawNavbarNoteList = false;
|
||||
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
|
||||
|
||||
angular.element(document).click(function() {
|
||||
$scope.query.q = '';
|
||||
});
|
||||
|
||||
getZeppelinVersion();
|
||||
loadNotes();
|
||||
}
|
||||
|
||||
function isActive(noteId) {
|
||||
return ($routeParams.noteId === noteId);
|
||||
}
|
||||
|
||||
function loadNotes() {
|
||||
websocketMsgSrv.getNoteList();
|
||||
}
|
||||
|
||||
function logout() {
|
||||
var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
|
||||
|
||||
//for firefox and safari
|
||||
logoutURL = logoutURL.replace('//', '//false:false@');
|
||||
$http.post(logoutURL).error(function() {
|
||||
//force authcBasic (if configured) to logout
|
||||
$http.post(logoutURL).error(function() {
|
||||
$rootScope.userName = '';
|
||||
$rootScope.ticket.principal = '';
|
||||
$rootScope.ticket.ticket = '';
|
||||
$rootScope.ticket.roles = '';
|
||||
BootstrapDialog.show({
|
||||
message: 'Logout Success'
|
||||
});
|
||||
setTimeout(function() {
|
||||
window.location.replace('/');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function search(searchTerm) {
|
||||
$location.path('/search/' + searchTerm);
|
||||
}
|
||||
|
||||
function showLoginWindow() {
|
||||
setTimeout(function() {
|
||||
angular.element('#userName').focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
noteListDataFactory.setNotes(notes);
|
||||
initNotebookListEventListener();
|
||||
});
|
||||
|
||||
$scope.$on('setConnectedStatus', function(event, param) {
|
||||
vm.connected = param;
|
||||
});
|
||||
|
||||
$scope.$on('loginSuccess', function(event, param) {
|
||||
loadNotes();
|
||||
});
|
||||
|
||||
/*
|
||||
** Performance optimization for Browser Render.
|
||||
*/
|
||||
function initNotebookListEventListener() {
|
||||
angular.element(document).ready(function() {
|
||||
angular.element('.notebook-list-dropdown').on('show.bs.dropdown', function() {
|
||||
$scope.isDrawNavbarNoteList = true;
|
||||
});
|
||||
|
||||
angular.element('.notebook-list-dropdown').on('hide.bs.dropdown', function() {
|
||||
$scope.isDrawNavbarNoteList = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,23 +11,21 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('ngEnter', ngEnter);
|
||||
angular.module('zeppelinWebApp').directive('ngEnter', ngEnter);
|
||||
|
||||
function ngEnter() {
|
||||
return function(scope, element, attrs) {
|
||||
element.bind('keydown keypress', function(event) {
|
||||
if (event.which === 13) {
|
||||
if (!event.shiftKey) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.ngEnter);
|
||||
});
|
||||
}
|
||||
event.preventDefault();
|
||||
function ngEnter() {
|
||||
return function(scope, element, attrs) {
|
||||
element.bind('keydown keypress', function(event) {
|
||||
if (event.which === 13) {
|
||||
if (!event.shiftKey) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.ngEnter);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,21 +11,19 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('ngEscape', ngEscape);
|
||||
angular.module('zeppelinWebApp').directive('ngEscape', ngEscape);
|
||||
|
||||
function ngEscape() {
|
||||
return function(scope, element, attrs) {
|
||||
element.bind('keydown keyup', function(event) {
|
||||
if (event.which === 27) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.ngEscape);
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
function ngEscape() {
|
||||
return function(scope, element, attrs) {
|
||||
element.bind('keydown keyup', function(event) {
|
||||
if (event.which === 27) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.ngEscape);
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,175 +11,173 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('noteActionSrv', noteActionSrv);
|
||||
angular.module('zeppelinWebApp').service('noteActionSrv', noteActionSrv);
|
||||
|
||||
noteActionSrv.$inject = ['websocketMsgSrv', '$location', 'renameSrv', 'noteListDataFactory'];
|
||||
noteActionSrv.$inject = ['websocketMsgSrv', '$location', 'renameSrv', 'noteListDataFactory'];
|
||||
|
||||
function noteActionSrv(websocketMsgSrv, $location, renameSrv, noteListDataFactory) {
|
||||
this.moveNoteToTrash = function(noteId, redirectToHome) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Move this note to trash?',
|
||||
message: 'This note will be moved to <strong>trash</strong>.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.moveNoteToTrash(noteId);
|
||||
if (redirectToHome) {
|
||||
$location.path('/');
|
||||
}
|
||||
function noteActionSrv(websocketMsgSrv, $location, renameSrv, noteListDataFactory) {
|
||||
this.moveNoteToTrash = function(noteId, redirectToHome) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Move this note to trash?',
|
||||
message: 'This note will be moved to <strong>trash</strong>.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.moveNoteToTrash(noteId);
|
||||
if (redirectToHome) {
|
||||
$location.path('/');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.moveFolderToTrash = function(folderId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Move this folder to trash?',
|
||||
message: 'This folder will be moved to <strong>trash</strong>.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.moveFolderToTrash(folderId);
|
||||
this.moveFolderToTrash = function(folderId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Move this folder to trash?',
|
||||
message: 'This folder will be moved to <strong>trash</strong>.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.moveFolderToTrash(folderId);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.removeNote = function(noteId, redirectToHome) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! This note will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.deleteNote(noteId);
|
||||
if (redirectToHome) {
|
||||
$location.path('/');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.removeNote = function(noteId, redirectToHome) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! This note will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.deleteNote(noteId);
|
||||
if (redirectToHome) {
|
||||
$location.path('/');
|
||||
}
|
||||
}
|
||||
this.removeFolder = function(folderId) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! This folder will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.removeFolder(folderId);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.removeFolder = function(folderId) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! This folder will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.removeFolder(folderId);
|
||||
}
|
||||
this.restoreAll = function() {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Are you sure want to restore all notes in the trash?',
|
||||
message: 'Folders and notes in the trash will be ' +
|
||||
'<strong>merged</strong> into their original position.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.restoreAll();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.restoreAll = function() {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: 'Are you sure want to restore all notes in the trash?',
|
||||
message: 'Folders and notes in the trash will be ' +
|
||||
'<strong>merged</strong> into their original position.',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.restoreAll();
|
||||
}
|
||||
this.emptyTrash = function() {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! Notes under trash will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.emptyTrash();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.emptyTrash = function() {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! Notes under trash will be removed permanently',
|
||||
message: 'This cannot be undone. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.emptyTrash();
|
||||
}
|
||||
this.clearAllParagraphOutput = function(noteId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Do you want to clear all output?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.clearAllParagraphOutput(noteId);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.clearAllParagraphOutput = function(noteId) {
|
||||
BootstrapDialog.confirm({
|
||||
closable: true,
|
||||
title: '',
|
||||
message: 'Do you want to clear all output?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.clearAllParagraphOutput(noteId);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
this.renameNote = function(noteId, notePath) {
|
||||
renameSrv.openRenameModal({
|
||||
title: 'Rename note',
|
||||
oldName: notePath,
|
||||
callback: function(newName) {
|
||||
websocketMsgSrv.renameNote(noteId, newName);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.renameNote = function(noteId, notePath) {
|
||||
renameSrv.openRenameModal({
|
||||
title: 'Rename note',
|
||||
oldName: notePath,
|
||||
callback: function(newName) {
|
||||
websocketMsgSrv.renameNote(noteId, newName);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.renameFolder = function(folderId) {
|
||||
renameSrv.openRenameModal({
|
||||
title: 'Rename folder',
|
||||
oldName: folderId,
|
||||
callback: function(newName) {
|
||||
var newFolderId = normalizeFolderId(newName);
|
||||
if (_.has(noteListDataFactory.flatFolderMap, newFolderId)) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! The folder will be MERGED',
|
||||
message: 'The folder will be merged into <strong>' + newFolderId + '</strong>. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.renameFolder(folderId, newFolderId);
|
||||
}
|
||||
this.renameFolder = function(folderId) {
|
||||
renameSrv.openRenameModal({
|
||||
title: 'Rename folder',
|
||||
oldName: folderId,
|
||||
callback: function(newName) {
|
||||
var newFolderId = normalizeFolderId(newName);
|
||||
if (_.has(noteListDataFactory.flatFolderMap, newFolderId)) {
|
||||
BootstrapDialog.confirm({
|
||||
type: BootstrapDialog.TYPE_WARNING,
|
||||
closable: true,
|
||||
title: 'WARNING! The folder will be MERGED',
|
||||
message: 'The folder will be merged into <strong>' + newFolderId + '</strong>. Are you sure?',
|
||||
callback: function(result) {
|
||||
if (result) {
|
||||
websocketMsgSrv.renameFolder(folderId, newFolderId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
websocketMsgSrv.renameFolder(folderId, newFolderId);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
websocketMsgSrv.renameFolder(folderId, newFolderId);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function normalizeFolderId(folderId) {
|
||||
folderId = folderId.trim();
|
||||
|
||||
while (folderId.indexOf('\\') > -1) {
|
||||
folderId = folderId.replace('\\', '/');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
while (folderId.indexOf('///') > -1) {
|
||||
folderId = folderId.replace('///', '/');
|
||||
}
|
||||
function normalizeFolderId(folderId) {
|
||||
folderId = folderId.trim();
|
||||
|
||||
folderId = folderId.replace('//', '/');
|
||||
|
||||
if (folderId === '/') {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (folderId[0] === '/') {
|
||||
folderId = folderId.substring(1);
|
||||
}
|
||||
|
||||
if (folderId.slice(-1) === '/') {
|
||||
folderId = folderId.slice(0, -1);
|
||||
}
|
||||
|
||||
return folderId;
|
||||
while (folderId.indexOf('\\') > -1) {
|
||||
folderId = folderId.replace('\\', '/');
|
||||
}
|
||||
|
||||
while (folderId.indexOf('///') > -1) {
|
||||
folderId = folderId.replace('///', '/');
|
||||
}
|
||||
|
||||
folderId = folderId.replace('//', '/');
|
||||
|
||||
if (folderId === '/') {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (folderId[0] === '/') {
|
||||
folderId = folderId.substring(1);
|
||||
}
|
||||
|
||||
if (folderId.slice(-1) === '/') {
|
||||
folderId = folderId.slice(0, -1);
|
||||
}
|
||||
|
||||
return folderId;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,74 +11,72 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').factory('noteListDataFactory', noteListDataFactory);
|
||||
angular.module('zeppelinWebApp').factory('noteListDataFactory', noteListDataFactory);
|
||||
|
||||
noteListDataFactory.$inject = ['TRASH_FOLDER_ID'];
|
||||
noteListDataFactory.$inject = ['TRASH_FOLDER_ID'];
|
||||
|
||||
function noteListDataFactory(TRASH_FOLDER_ID) {
|
||||
var notes = {
|
||||
root: {children: []},
|
||||
flatList: [],
|
||||
flatFolderMap: {},
|
||||
function noteListDataFactory(TRASH_FOLDER_ID) {
|
||||
var notes = {
|
||||
root: {children: []},
|
||||
flatList: [],
|
||||
flatFolderMap: {},
|
||||
|
||||
setNotes: function(notesList) {
|
||||
// a flat list to boost searching
|
||||
notes.flatList = _.map(notesList, (note) => {
|
||||
note.isTrash = note.name ?
|
||||
note.name.split('/')[0] === TRASH_FOLDER_ID : false;
|
||||
return note;
|
||||
});
|
||||
setNotes: function(notesList) {
|
||||
// a flat list to boost searching
|
||||
notes.flatList = _.map(notesList, (note) => {
|
||||
note.isTrash = note.name ?
|
||||
note.name.split('/')[0] === TRASH_FOLDER_ID : false;
|
||||
return note;
|
||||
});
|
||||
|
||||
// construct the folder-based tree
|
||||
notes.root = {children: []};
|
||||
notes.flatFolderMap = {};
|
||||
_.reduce(notesList, function(root, note) {
|
||||
var noteName = note.name || note.id;
|
||||
var nodes = noteName.match(/([^\/][^\/]*)/g);
|
||||
// construct the folder-based tree
|
||||
notes.root = {children: []};
|
||||
notes.flatFolderMap = {};
|
||||
_.reduce(notesList, function(root, note) {
|
||||
var noteName = note.name || note.id;
|
||||
var nodes = noteName.match(/([^\/][^\/]*)/g);
|
||||
|
||||
// recursively add nodes
|
||||
addNode(root, nodes, note.id);
|
||||
// recursively add nodes
|
||||
addNode(root, nodes, note.id);
|
||||
|
||||
return root;
|
||||
}, notes.root);
|
||||
}
|
||||
};
|
||||
return root;
|
||||
}, notes.root);
|
||||
}
|
||||
};
|
||||
|
||||
var addNode = function(curDir, nodes, noteId) {
|
||||
if (nodes.length === 1) { // the leaf
|
||||
curDir.children.push({
|
||||
name: nodes[0],
|
||||
id: noteId,
|
||||
path: curDir.id ? curDir.id + '/' + nodes[0] : nodes[0],
|
||||
var addNode = function(curDir, nodes, noteId) {
|
||||
if (nodes.length === 1) { // the leaf
|
||||
curDir.children.push({
|
||||
name: nodes[0],
|
||||
id: noteId,
|
||||
path: curDir.id ? curDir.id + '/' + nodes[0] : nodes[0],
|
||||
isTrash: curDir.id ? curDir.id.split('/')[0] === TRASH_FOLDER_ID : false
|
||||
});
|
||||
} else { // a folder node
|
||||
var node = nodes.shift();
|
||||
var dir = _.find(curDir.children,
|
||||
function(c) {return c.name === node && c.children !== undefined;});
|
||||
if (dir !== undefined) { // found an existing dir
|
||||
addNode(dir, nodes, noteId);
|
||||
} else {
|
||||
var newDir = {
|
||||
id: curDir.id ? curDir.id + '/' + node : node,
|
||||
name: node,
|
||||
hidden: true,
|
||||
children: [],
|
||||
isTrash: curDir.id ? curDir.id.split('/')[0] === TRASH_FOLDER_ID : false
|
||||
});
|
||||
} else { // a folder node
|
||||
var node = nodes.shift();
|
||||
var dir = _.find(curDir.children,
|
||||
function(c) {return c.name === node && c.children !== undefined;});
|
||||
if (dir !== undefined) { // found an existing dir
|
||||
addNode(dir, nodes, noteId);
|
||||
} else {
|
||||
var newDir = {
|
||||
id: curDir.id ? curDir.id + '/' + node : node,
|
||||
name: node,
|
||||
hidden: true,
|
||||
children: [],
|
||||
isTrash: curDir.id ? curDir.id.split('/')[0] === TRASH_FOLDER_ID : false
|
||||
};
|
||||
};
|
||||
|
||||
// add the folder to flat folder map
|
||||
notes.flatFolderMap[newDir.id] = newDir;
|
||||
// add the folder to flat folder map
|
||||
notes.flatFolderMap[newDir.id] = newDir;
|
||||
|
||||
curDir.children.push(newDir);
|
||||
addNode(newDir, nodes, noteId);
|
||||
}
|
||||
curDir.children.push(newDir);
|
||||
addNode(newDir, nodes, noteId);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return notes;
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,104 +11,102 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NotenameCtrl', NotenameCtrl);
|
||||
angular.module('zeppelinWebApp').controller('NotenameCtrl', NotenameCtrl);
|
||||
|
||||
NotenameCtrl.$inject = [
|
||||
'$scope',
|
||||
'noteListDataFactory',
|
||||
'$routeParams',
|
||||
'websocketMsgSrv'
|
||||
];
|
||||
NotenameCtrl.$inject = [
|
||||
'$scope',
|
||||
'noteListDataFactory',
|
||||
'$routeParams',
|
||||
'websocketMsgSrv'
|
||||
];
|
||||
|
||||
function NotenameCtrl($scope, noteListDataFactory, $routeParams, websocketMsgSrv) {
|
||||
var vm = this;
|
||||
vm.clone = false;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
$scope.note = {};
|
||||
$scope.interpreterSettings = {};
|
||||
$scope.note.defaultInterpreter = null;
|
||||
function NotenameCtrl($scope, noteListDataFactory, $routeParams, websocketMsgSrv) {
|
||||
var vm = this;
|
||||
vm.clone = false;
|
||||
vm.notes = noteListDataFactory;
|
||||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
$scope.note = {};
|
||||
$scope.interpreterSettings = {};
|
||||
$scope.note.defaultInterpreter = null;
|
||||
|
||||
vm.createNote = function() {
|
||||
if (!vm.clone) {
|
||||
var defaultInterpreterId = '';
|
||||
if ($scope.note.defaultInterpreter !== null) {
|
||||
defaultInterpreterId = $scope.note.defaultInterpreter.id;
|
||||
}
|
||||
vm.websocketMsgSrv.createNotebook($scope.note.notename, defaultInterpreterId);
|
||||
$scope.note.defaultInterpreter = $scope.interpreterSettings[0];
|
||||
} else {
|
||||
var noteId = $routeParams.noteId;
|
||||
vm.websocketMsgSrv.cloneNote(noteId, $scope.note.notename);
|
||||
vm.createNote = function() {
|
||||
if (!vm.clone) {
|
||||
var defaultInterpreterId = '';
|
||||
if ($scope.note.defaultInterpreter !== null) {
|
||||
defaultInterpreterId = $scope.note.defaultInterpreter.id;
|
||||
}
|
||||
};
|
||||
vm.websocketMsgSrv.createNotebook($scope.note.notename, defaultInterpreterId);
|
||||
$scope.note.defaultInterpreter = $scope.interpreterSettings[0];
|
||||
} else {
|
||||
var noteId = $routeParams.noteId;
|
||||
vm.websocketMsgSrv.cloneNote(noteId, $scope.note.notename);
|
||||
}
|
||||
};
|
||||
|
||||
vm.handleNameEnter = function() {
|
||||
angular.element('#noteNameModal').modal('toggle');
|
||||
vm.createNote();
|
||||
};
|
||||
vm.handleNameEnter = function() {
|
||||
angular.element('#noteNameModal').modal('toggle');
|
||||
vm.createNote();
|
||||
};
|
||||
|
||||
vm.preVisible = function(clone, sourceNoteName) {
|
||||
vm.clone = clone;
|
||||
vm.sourceNoteName = sourceNoteName;
|
||||
$scope.note.notename = vm.clone ? vm.cloneNoteName() : vm.newNoteName();
|
||||
$scope.$apply();
|
||||
};
|
||||
vm.preVisible = function(clone, sourceNoteName) {
|
||||
vm.clone = clone;
|
||||
vm.sourceNoteName = sourceNoteName;
|
||||
$scope.note.notename = vm.clone ? vm.cloneNoteName() : vm.newNoteName();
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
vm.newNoteName = function() {
|
||||
var newCount = 1;
|
||||
angular.forEach(vm.notes.flatList, function(noteName) {
|
||||
noteName = noteName.name;
|
||||
if (noteName.match(/^Untitled Note [0-9]*$/)) {
|
||||
var lastCount = noteName.substr(14) * 1;
|
||||
if (newCount <= lastCount) {
|
||||
newCount = lastCount + 1;
|
||||
}
|
||||
vm.newNoteName = function() {
|
||||
var newCount = 1;
|
||||
angular.forEach(vm.notes.flatList, function(noteName) {
|
||||
noteName = noteName.name;
|
||||
if (noteName.match(/^Untitled Note [0-9]*$/)) {
|
||||
var lastCount = noteName.substr(14) * 1;
|
||||
if (newCount <= lastCount) {
|
||||
newCount = lastCount + 1;
|
||||
}
|
||||
});
|
||||
return 'Untitled Note ' + newCount;
|
||||
};
|
||||
|
||||
vm.cloneNoteName = function() {
|
||||
var copyCount = 1;
|
||||
var newCloneName = '';
|
||||
var lastIndex = vm.sourceNoteName.lastIndexOf(' ');
|
||||
var endsWithNumber = !!vm.sourceNoteName.match('^.+?\\s\\d$');
|
||||
var noteNamePrefix = endsWithNumber ? vm.sourceNoteName.substr(0, lastIndex) : vm.sourceNoteName;
|
||||
var regexp = new RegExp('^' + noteNamePrefix + ' .+');
|
||||
|
||||
angular.forEach(vm.notes.flatList, function(noteName) {
|
||||
noteName = noteName.name;
|
||||
if (noteName.match(regexp)) {
|
||||
var lastCopyCount = noteName.substr(lastIndex).trim();
|
||||
newCloneName = noteNamePrefix;
|
||||
lastCopyCount = parseInt(lastCopyCount);
|
||||
if (copyCount <= lastCopyCount) {
|
||||
copyCount = lastCopyCount + 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!newCloneName) {
|
||||
newCloneName = vm.sourceNoteName;
|
||||
}
|
||||
return newCloneName + ' ' + copyCount;
|
||||
};
|
||||
});
|
||||
return 'Untitled Note ' + newCount;
|
||||
};
|
||||
|
||||
vm.getInterpreterSettings = function() {
|
||||
vm.websocketMsgSrv.getInterpreterSettings();
|
||||
};
|
||||
|
||||
vm.cloneNoteName = function() {
|
||||
var copyCount = 1;
|
||||
var newCloneName = '';
|
||||
var lastIndex = vm.sourceNoteName.lastIndexOf(' ');
|
||||
var endsWithNumber = !!vm.sourceNoteName.match('^.+?\\s\\d$');
|
||||
var noteNamePrefix = endsWithNumber ? vm.sourceNoteName.substr(0, lastIndex) : vm.sourceNoteName;
|
||||
var regexp = new RegExp('^' + noteNamePrefix + ' .+');
|
||||
|
||||
$scope.$on('interpreterSettings', function(event, data) {
|
||||
$scope.interpreterSettings = data.interpreterSettings;
|
||||
|
||||
//initialize default interpreter with Spark interpreter
|
||||
$scope.note.defaultInterpreter = data.interpreterSettings[0];
|
||||
angular.forEach(vm.notes.flatList, function(noteName) {
|
||||
noteName = noteName.name;
|
||||
if (noteName.match(regexp)) {
|
||||
var lastCopyCount = noteName.substr(lastIndex).trim();
|
||||
newCloneName = noteNamePrefix;
|
||||
lastCopyCount = parseInt(lastCopyCount);
|
||||
if (copyCount <= lastCopyCount) {
|
||||
copyCount = lastCopyCount + 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
if (!newCloneName) {
|
||||
newCloneName = vm.sourceNoteName;
|
||||
}
|
||||
return newCloneName + ' ' + copyCount;
|
||||
};
|
||||
|
||||
vm.getInterpreterSettings = function() {
|
||||
vm.websocketMsgSrv.getInterpreterSettings();
|
||||
};
|
||||
|
||||
|
||||
$scope.$on('interpreterSettings', function(event, data) {
|
||||
$scope.interpreterSettings = data.interpreterSettings;
|
||||
|
||||
//initialize default interpreter with Spark interpreter
|
||||
$scope.note.defaultInterpreter = data.interpreterSettings[0];
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,37 +11,35 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('modalvisible', modalvisible);
|
||||
angular.module('zeppelinWebApp').directive('modalvisible', modalvisible);
|
||||
|
||||
function modalvisible() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
preVisibleCallback: '&previsiblecallback',
|
||||
postVisibleCallback: '&postvisiblecallback',
|
||||
targetinput: '@targetinput'
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
// Add some listeners
|
||||
var previsibleMethod = scope.preVisibleCallback;
|
||||
var postVisibleMethod = scope.postVisibleCallback;
|
||||
element.on('show.bs.modal',function(e) {
|
||||
var relatedTarget = angular.element(e.relatedTarget);
|
||||
var clone = relatedTarget.data('clone');
|
||||
var sourceNoteName = relatedTarget.data('source-note-name');
|
||||
var cloneNote = clone ? true : false;
|
||||
previsibleMethod()(cloneNote, sourceNoteName);
|
||||
});
|
||||
element.on('shown.bs.modal', function(e) {
|
||||
if (scope.targetinput) {
|
||||
angular.element(e.target).find('input#' + scope.targetinput).select();
|
||||
}
|
||||
postVisibleMethod();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
function modalvisible() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
preVisibleCallback: '&previsiblecallback',
|
||||
postVisibleCallback: '&postvisiblecallback',
|
||||
targetinput: '@targetinput'
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
// Add some listeners
|
||||
var previsibleMethod = scope.preVisibleCallback;
|
||||
var postVisibleMethod = scope.postVisibleCallback;
|
||||
element.on('show.bs.modal',function(e) {
|
||||
var relatedTarget = angular.element(e.relatedTarget);
|
||||
var clone = relatedTarget.data('clone');
|
||||
var sourceNoteName = relatedTarget.data('source-note-name');
|
||||
var cloneNote = clone ? true : false;
|
||||
previsibleMethod()(cloneNote, sourceNoteName);
|
||||
});
|
||||
element.on('shown.bs.modal', function(e) {
|
||||
if (scope.targetinput) {
|
||||
angular.element(e.target).find('input#' + scope.targetinput).select();
|
||||
}
|
||||
postVisibleMethod();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -1,140 +1,138 @@
|
|||
/*
|
||||
* Licensed 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.
|
||||
*/
|
||||
(function() {
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NoteImportCtrl', NoteImportCtrl);
|
||||
angular.module('zeppelinWebApp').controller('NoteImportCtrl', NoteImportCtrl);
|
||||
|
||||
NoteImportCtrl.$inject = ['$scope', '$timeout', 'websocketMsgSrv'];
|
||||
NoteImportCtrl.$inject = ['$scope', '$timeout', 'websocketMsgSrv'];
|
||||
|
||||
function NoteImportCtrl($scope, $timeout, websocketMsgSrv) {
|
||||
var vm = this;
|
||||
function NoteImportCtrl($scope, $timeout, websocketMsgSrv) {
|
||||
var vm = this;
|
||||
$scope.note = {};
|
||||
$scope.note.step1 = true;
|
||||
$scope.note.step2 = false;
|
||||
$scope.maxLimit = '';
|
||||
var limit = 0;
|
||||
|
||||
websocketMsgSrv.listConfigurations();
|
||||
$scope.$on('configurationsInfo', function(scope, event) {
|
||||
limit = event.configurations['zeppelin.websocket.max.text.message.size'];
|
||||
$scope.maxLimit = Math.round(limit / 1048576);
|
||||
});
|
||||
|
||||
vm.resetFlags = function() {
|
||||
$scope.note = {};
|
||||
$scope.note.step1 = true;
|
||||
$scope.note.step2 = false;
|
||||
$scope.maxLimit = '';
|
||||
var limit = 0;
|
||||
angular.element('#noteImportFile').val('');
|
||||
};
|
||||
|
||||
websocketMsgSrv.listConfigurations();
|
||||
$scope.$on('configurationsInfo', function(scope, event) {
|
||||
limit = event.configurations['zeppelin.websocket.max.text.message.size'];
|
||||
$scope.maxLimit = Math.round(limit / 1048576);
|
||||
});
|
||||
$scope.uploadFile = function() {
|
||||
angular.element('#noteImportFile').click();
|
||||
};
|
||||
|
||||
vm.resetFlags = function() {
|
||||
$scope.note = {};
|
||||
$scope.importFile = function(element) {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.importFile = element.files[0];
|
||||
var file = $scope.note.importFile;
|
||||
var reader = new FileReader();
|
||||
|
||||
if (file.size > limit) {
|
||||
$scope.note.errorText = 'File size limit Exceeded!';
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
reader.onloadend = function() {
|
||||
vm.processImportJson(reader.result);
|
||||
};
|
||||
|
||||
if (file) {
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uploadURL = function() {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.step1 = false;
|
||||
$timeout(function() {
|
||||
$scope.note.step2 = true;
|
||||
}, 400);
|
||||
};
|
||||
|
||||
vm.importBack = function() {
|
||||
$scope.note.errorText = '';
|
||||
$timeout(function() {
|
||||
$scope.note.step1 = true;
|
||||
$scope.note.step2 = false;
|
||||
angular.element('#noteImportFile').val('');
|
||||
};
|
||||
}, 400);
|
||||
$scope.note.step2 = false;
|
||||
};
|
||||
|
||||
$scope.uploadFile = function() {
|
||||
angular.element('#noteImportFile').click();
|
||||
};
|
||||
vm.importNote = function() {
|
||||
$scope.note.errorText = '';
|
||||
if ($scope.note.importUrl) {
|
||||
jQuery.ajax({
|
||||
url: $scope.note.importUrl,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
xhrFields: {
|
||||
withCredentials: false
|
||||
},
|
||||
error: function(xhr, ajaxOptions, thrownError) {
|
||||
$scope.note.errorText = 'Unable to Fetch URL';
|
||||
$scope.$apply();
|
||||
}}).done(function(data) {
|
||||
vm.processImportJson(data);
|
||||
});
|
||||
} else {
|
||||
$scope.note.errorText = 'Enter URL';
|
||||
$scope.$apply();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.importFile = function(element) {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.importFile = element.files[0];
|
||||
var file = $scope.note.importFile;
|
||||
var reader = new FileReader();
|
||||
|
||||
if (file.size > limit) {
|
||||
$scope.note.errorText = 'File size limit Exceeded!';
|
||||
vm.processImportJson = function(result) {
|
||||
if (typeof result !== 'object') {
|
||||
try {
|
||||
result = JSON.parse(result);
|
||||
} catch (e) {
|
||||
$scope.note.errorText = 'JSON parse exception';
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
reader.onloadend = function() {
|
||||
vm.processImportJson(reader.result);
|
||||
};
|
||||
|
||||
if (file) {
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uploadURL = function() {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.step1 = false;
|
||||
$timeout(function() {
|
||||
$scope.note.step2 = true;
|
||||
}, 400);
|
||||
};
|
||||
|
||||
vm.importBack = function() {
|
||||
$scope.note.errorText = '';
|
||||
$timeout(function() {
|
||||
$scope.note.step1 = true;
|
||||
}, 400);
|
||||
$scope.note.step2 = false;
|
||||
};
|
||||
|
||||
vm.importNote = function() {
|
||||
$scope.note.errorText = '';
|
||||
if ($scope.note.importUrl) {
|
||||
jQuery.ajax({
|
||||
url: $scope.note.importUrl,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
xhrFields: {
|
||||
withCredentials: false
|
||||
},
|
||||
error: function(xhr, ajaxOptions, thrownError) {
|
||||
$scope.note.errorText = 'Unable to Fetch URL';
|
||||
$scope.$apply();
|
||||
}}).done(function(data) {
|
||||
vm.processImportJson(data);
|
||||
});
|
||||
}
|
||||
if (result.paragraphs && result.paragraphs.length > 0) {
|
||||
if (!$scope.note.noteImportName) {
|
||||
$scope.note.noteImportName = result.name;
|
||||
} else {
|
||||
$scope.note.errorText = 'Enter URL';
|
||||
$scope.$apply();
|
||||
result.name = $scope.note.noteImportName;
|
||||
}
|
||||
};
|
||||
websocketMsgSrv.importNote(result);
|
||||
//angular.element('#noteImportModal').modal('hide');
|
||||
} else {
|
||||
$scope.note.errorText = 'Invalid JSON';
|
||||
}
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
vm.processImportJson = function(result) {
|
||||
if (typeof result !== 'object') {
|
||||
try {
|
||||
result = JSON.parse(result);
|
||||
} catch (e) {
|
||||
$scope.note.errorText = 'JSON parse exception';
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
}
|
||||
if (result.paragraphs && result.paragraphs.length > 0) {
|
||||
if (!$scope.note.noteImportName) {
|
||||
$scope.note.noteImportName = result.name;
|
||||
} else {
|
||||
result.name = $scope.note.noteImportName;
|
||||
}
|
||||
websocketMsgSrv.importNote(result);
|
||||
//angular.element('#noteImportModal').modal('hide');
|
||||
} else {
|
||||
$scope.note.errorText = 'Invalid JSON';
|
||||
}
|
||||
$scope.$apply();
|
||||
};
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
vm.resetFlags();
|
||||
angular.element('#noteImportModal').modal('hide');
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
** $scope.$on functions below
|
||||
*/
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
vm.resetFlags();
|
||||
angular.element('#noteImportModal').modal('hide');
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,31 +11,29 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('noteVarShareService', noteVarShareService);
|
||||
angular.module('zeppelinWebApp').service('noteVarShareService', noteVarShareService);
|
||||
|
||||
noteVarShareService.$inject = [];
|
||||
noteVarShareService.$inject = [];
|
||||
|
||||
function noteVarShareService() {
|
||||
var store = {};
|
||||
function noteVarShareService() {
|
||||
var store = {};
|
||||
|
||||
this.clear = function() {
|
||||
store = {};
|
||||
};
|
||||
|
||||
this.put = function(key, value) {
|
||||
store[key] = value;
|
||||
};
|
||||
|
||||
this.get = function(key) {
|
||||
return store[key];
|
||||
};
|
||||
|
||||
this.del = function(key) {
|
||||
var v = store[key];
|
||||
delete store[key];
|
||||
return v;
|
||||
};
|
||||
this.clear = function() {
|
||||
store = {};
|
||||
};
|
||||
})();
|
||||
|
||||
this.put = function(key, value) {
|
||||
store[key] = value;
|
||||
};
|
||||
|
||||
this.get = function(key) {
|
||||
return store[key];
|
||||
};
|
||||
|
||||
this.del = function(key) {
|
||||
var v = store[key];
|
||||
delete store[key];
|
||||
return v;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,17 +11,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafePopup', popoverHtmlUnsafePopup);
|
||||
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafePopup', popoverHtmlUnsafePopup);
|
||||
|
||||
function popoverHtmlUnsafePopup() {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
scope: {title: '@', content: '@', placement: '@', animation: '&', isOpen: '&'},
|
||||
templateUrl: 'components/popover-html-unsafe/popover-html-unsafe-popup.html'
|
||||
};
|
||||
}
|
||||
function popoverHtmlUnsafePopup() {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
scope: {title: '@', content: '@', placement: '@', animation: '&', isOpen: '&'},
|
||||
templateUrl: 'components/popover-html-unsafe/popover-html-unsafe-popup.html'
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,14 +11,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafe', popoverHtmlUnsafe);
|
||||
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafe', popoverHtmlUnsafe);
|
||||
|
||||
popoverHtmlUnsafe.$inject = ['$tooltip'];
|
||||
popoverHtmlUnsafe.$inject = ['$tooltip'];
|
||||
|
||||
function popoverHtmlUnsafe($tooltip) {
|
||||
return $tooltip('popoverHtmlUnsafe', 'popover', 'click');
|
||||
}
|
||||
function popoverHtmlUnsafe($tooltip) {
|
||||
return $tooltip('popoverHtmlUnsafe', 'popover', 'click');
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,39 +11,37 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').controller('RenameCtrl', RenameCtrl);
|
||||
angular.module('zeppelinWebApp').controller('RenameCtrl', RenameCtrl);
|
||||
|
||||
RenameCtrl.$inject = ['$scope'];
|
||||
RenameCtrl.$inject = ['$scope'];
|
||||
|
||||
function RenameCtrl($scope) {
|
||||
var self = this;
|
||||
function RenameCtrl($scope) {
|
||||
var self = this;
|
||||
|
||||
$scope.params = {newName: ''};
|
||||
$scope.isValid = true;
|
||||
$scope.params = {newName: ''};
|
||||
$scope.isValid = true;
|
||||
|
||||
$scope.rename = function() {
|
||||
angular.element('#renameModal').modal('hide');
|
||||
self.callback($scope.params.newName);
|
||||
$scope.rename = function() {
|
||||
angular.element('#renameModal').modal('hide');
|
||||
self.callback($scope.params.newName);
|
||||
};
|
||||
|
||||
$scope.$on('openRenameModal', function(event, options) {
|
||||
self.validator = options.validator || defaultValidator;
|
||||
self.callback = options.callback || function() {};
|
||||
|
||||
$scope.title = options.title || 'Rename';
|
||||
$scope.params.newName = options.oldName || '';
|
||||
$scope.validate = function() {
|
||||
$scope.isValid = self.validator($scope.params.newName);
|
||||
};
|
||||
|
||||
$scope.$on('openRenameModal', function(event, options) {
|
||||
self.validator = options.validator || defaultValidator;
|
||||
self.callback = options.callback || function() {};
|
||||
angular.element('#renameModal').modal('show');
|
||||
});
|
||||
|
||||
$scope.title = options.title || 'Rename';
|
||||
$scope.params.newName = options.oldName || '';
|
||||
$scope.validate = function() {
|
||||
$scope.isValid = self.validator($scope.params.newName);
|
||||
};
|
||||
|
||||
angular.element('#renameModal').modal('show');
|
||||
});
|
||||
|
||||
function defaultValidator(str) {
|
||||
return !!str.trim();
|
||||
}
|
||||
function defaultValidator(str) {
|
||||
return !!str.trim();
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,24 +11,22 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('renameSrv', renameSrv);
|
||||
angular.module('zeppelinWebApp').service('renameSrv', renameSrv);
|
||||
|
||||
renameSrv.$inject = ['$rootScope'];
|
||||
renameSrv.$inject = ['$rootScope'];
|
||||
|
||||
function renameSrv($rootScope) {
|
||||
var self = this;
|
||||
function renameSrv($rootScope) {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* <options schema>
|
||||
* title: string - Modal title
|
||||
* oldName: string - name to initialize input
|
||||
* callback: (newName: string)=>void - callback onButtonClick
|
||||
* validator: (str: string)=>boolean - input validator
|
||||
*/
|
||||
self.openRenameModal = function(options) {
|
||||
$rootScope.$broadcast('openRenameModal', options);
|
||||
};
|
||||
}
|
||||
})();
|
||||
/**
|
||||
* <options schema>
|
||||
* title: string - Modal title
|
||||
* oldName: string - name to initialize input
|
||||
* callback: (newName: string)=>void - callback onButtonClick
|
||||
* validator: (str: string)=>boolean - input validator
|
||||
*/
|
||||
self.openRenameModal = function(options) {
|
||||
$rootScope.$broadcast('openRenameModal', options);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,62 +11,60 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').directive('resizable', resizable);
|
||||
angular.module('zeppelinWebApp').directive('resizable', resizable);
|
||||
|
||||
function resizable() {
|
||||
var resizableConfig = {
|
||||
autoHide: true,
|
||||
handles: 'se',
|
||||
helper: 'resizable-helper',
|
||||
stop: function() {
|
||||
angular.element(this).css({'width': '100%', 'height': '100%'});
|
||||
}
|
||||
};
|
||||
function resizable() {
|
||||
var resizableConfig = {
|
||||
autoHide: true,
|
||||
handles: 'se',
|
||||
helper: 'resizable-helper',
|
||||
stop: function() {
|
||||
angular.element(this).css({'width': '100%', 'height': '100%'});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
callback: '&onResize'
|
||||
},
|
||||
link: function postLink(scope, elem, attrs) {
|
||||
attrs.$observe('resize', function(resize) {
|
||||
var resetResize = function(elem, resize) {
|
||||
var colStep = window.innerWidth / 12;
|
||||
elem.off('resizestop');
|
||||
var conf = angular.copy(resizableConfig);
|
||||
if (resize.graphType === 'TABLE' || resize.graphType === 'TEXT') {
|
||||
conf.grid = [colStep, 10];
|
||||
conf.minHeight = 100;
|
||||
} else {
|
||||
conf.grid = [colStep, 10000];
|
||||
conf.minHeight = 0;
|
||||
}
|
||||
conf.maxWidth = window.innerWidth;
|
||||
|
||||
elem.resizable(conf);
|
||||
elem.on('resizestop', function() {
|
||||
if (scope.callback) {
|
||||
var height = elem.height();
|
||||
if (height < 50) {
|
||||
height = 300;
|
||||
}
|
||||
scope.callback({width: Math.ceil(elem.width() / colStep), height: height});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
resize = JSON.parse(resize);
|
||||
if (resize.allowresize === 'true') {
|
||||
resetResize(elem, resize);
|
||||
angular.element(window).resize(function() {
|
||||
resetResize(elem, resize);
|
||||
});
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
callback: '&onResize'
|
||||
},
|
||||
link: function postLink(scope, elem, attrs) {
|
||||
attrs.$observe('resize', function(resize) {
|
||||
var resetResize = function(elem, resize) {
|
||||
var colStep = window.innerWidth / 12;
|
||||
elem.off('resizestop');
|
||||
var conf = angular.copy(resizableConfig);
|
||||
if (resize.graphType === 'TABLE' || resize.graphType === 'TEXT') {
|
||||
conf.grid = [colStep, 10];
|
||||
conf.minHeight = 100;
|
||||
} else {
|
||||
conf.grid = [colStep, 10000];
|
||||
conf.minHeight = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
conf.maxWidth = window.innerWidth;
|
||||
|
||||
elem.resizable(conf);
|
||||
elem.on('resizestop', function() {
|
||||
if (scope.callback) {
|
||||
var height = elem.height();
|
||||
if (height < 50) {
|
||||
height = 300;
|
||||
}
|
||||
scope.callback({width: Math.ceil(elem.width() / colStep), height: height});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
resize = JSON.parse(resize);
|
||||
if (resize.allowresize === 'true') {
|
||||
resetResize(elem, resize);
|
||||
angular.element(window).resize(function() {
|
||||
resetResize(elem, resize);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,44 +11,42 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('saveAsService', saveAsService);
|
||||
angular.module('zeppelinWebApp').service('saveAsService', saveAsService);
|
||||
|
||||
saveAsService.$inject = ['browserDetectService'];
|
||||
saveAsService.$inject = ['browserDetectService'];
|
||||
|
||||
function saveAsService(browserDetectService) {
|
||||
this.saveAs = function(content, filename, extension) {
|
||||
var BOM = '\uFEFF';
|
||||
if (browserDetectService.detectIE()) {
|
||||
angular.element('body').append('<iframe id="SaveAsId" style="display: none"></iframe>');
|
||||
var frameSaveAs = angular.element('body > iframe#SaveAsId')[0].contentWindow;
|
||||
content = BOM + content;
|
||||
frameSaveAs.document.open('text/json', 'replace');
|
||||
frameSaveAs.document.write(content);
|
||||
frameSaveAs.document.close();
|
||||
frameSaveAs.focus();
|
||||
var t1 = Date.now();
|
||||
frameSaveAs.document.execCommand('SaveAs', false, filename + '.' + extension);
|
||||
var t2 = Date.now();
|
||||
function saveAsService(browserDetectService) {
|
||||
this.saveAs = function(content, filename, extension) {
|
||||
var BOM = '\uFEFF';
|
||||
if (browserDetectService.detectIE()) {
|
||||
angular.element('body').append('<iframe id="SaveAsId" style="display: none"></iframe>');
|
||||
var frameSaveAs = angular.element('body > iframe#SaveAsId')[0].contentWindow;
|
||||
content = BOM + content;
|
||||
frameSaveAs.document.open('text/json', 'replace');
|
||||
frameSaveAs.document.write(content);
|
||||
frameSaveAs.document.close();
|
||||
frameSaveAs.focus();
|
||||
var t1 = Date.now();
|
||||
frameSaveAs.document.execCommand('SaveAs', false, filename + '.' + extension);
|
||||
var t2 = Date.now();
|
||||
|
||||
//This means, this version of IE dosen't support auto download of a file with extension provided in param
|
||||
//falling back to ".txt"
|
||||
if (t1 === t2) {
|
||||
frameSaveAs.document.execCommand('SaveAs', true, filename + '.txt');
|
||||
}
|
||||
angular.element('body > iframe#SaveAsId').remove();
|
||||
} else {
|
||||
content = 'data:image/svg;charset=utf-8,' + BOM + encodeURIComponent(content);
|
||||
angular.element('body').append('<a id="SaveAsId"></a>');
|
||||
var saveAsElement = angular.element('body > a#SaveAsId');
|
||||
saveAsElement.attr('href', content);
|
||||
saveAsElement.attr('download', filename + '.' + extension);
|
||||
saveAsElement.attr('target', '_blank');
|
||||
saveAsElement[0].click();
|
||||
saveAsElement.remove();
|
||||
//This means, this version of IE dosen't support auto download of a file with extension provided in param
|
||||
//falling back to ".txt"
|
||||
if (t1 === t2) {
|
||||
frameSaveAs.document.execCommand('SaveAs', true, filename + '.txt');
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.element('body > iframe#SaveAsId').remove();
|
||||
} else {
|
||||
content = 'data:image/svg;charset=utf-8,' + BOM + encodeURIComponent(content);
|
||||
angular.element('body').append('<a id="SaveAsId"></a>');
|
||||
var saveAsElement = angular.element('body > a#SaveAsId');
|
||||
saveAsElement.attr('href', content);
|
||||
saveAsElement.attr('download', filename + '.' + extension);
|
||||
saveAsElement.attr('target', '_blank');
|
||||
saveAsElement[0].click();
|
||||
saveAsElement.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,26 +11,24 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('searchService', searchService);
|
||||
angular.module('zeppelinWebApp').service('searchService', searchService);
|
||||
|
||||
searchService.$inject = ['$resource', 'baseUrlSrv'];
|
||||
searchService.$inject = ['$resource', 'baseUrlSrv'];
|
||||
|
||||
function searchService($resource, baseUrlSrv) {
|
||||
this.search = function(term) {
|
||||
this.searchTerm = term.q;
|
||||
console.log('Searching for: %o', term.q);
|
||||
if (!term.q) { //TODO(bzz): empty string check
|
||||
return;
|
||||
}
|
||||
var encQuery = window.encodeURIComponent(term.q);
|
||||
return $resource(baseUrlSrv.getRestApiBase() + '/notebook/search?q=' + encQuery, {}, {
|
||||
query: {method: 'GET'}
|
||||
});
|
||||
};
|
||||
function searchService($resource, baseUrlSrv) {
|
||||
this.search = function(term) {
|
||||
this.searchTerm = term.q;
|
||||
console.log('Searching for: %o', term.q);
|
||||
if (!term.q) { //TODO(bzz): empty string check
|
||||
return;
|
||||
}
|
||||
var encQuery = window.encodeURIComponent(term.q);
|
||||
return $resource(baseUrlSrv.getRestApiBase() + '/notebook/search?q=' + encQuery, {}, {
|
||||
query: {method: 'GET'}
|
||||
});
|
||||
};
|
||||
|
||||
this.searchTerm = '';
|
||||
}
|
||||
this.searchTerm = '';
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,176 +11,174 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').factory('websocketEvents', websocketEvents);
|
||||
angular.module('zeppelinWebApp').factory('websocketEvents', websocketEvents);
|
||||
|
||||
websocketEvents.$inject = ['$rootScope', '$websocket', '$location', 'baseUrlSrv'];
|
||||
websocketEvents.$inject = ['$rootScope', '$websocket', '$location', 'baseUrlSrv'];
|
||||
|
||||
function websocketEvents($rootScope, $websocket, $location, baseUrlSrv) {
|
||||
var websocketCalls = {};
|
||||
var pingIntervalId;
|
||||
function websocketEvents($rootScope, $websocket, $location, baseUrlSrv) {
|
||||
var websocketCalls = {};
|
||||
var pingIntervalId;
|
||||
|
||||
websocketCalls.ws = $websocket(baseUrlSrv.getWebsocketUrl());
|
||||
websocketCalls.ws.reconnectIfNotNormalClose = true;
|
||||
websocketCalls.ws = $websocket(baseUrlSrv.getWebsocketUrl());
|
||||
websocketCalls.ws.reconnectIfNotNormalClose = true;
|
||||
|
||||
websocketCalls.ws.onOpen(function() {
|
||||
console.log('Websocket created');
|
||||
$rootScope.$broadcast('setConnectedStatus', true);
|
||||
pingIntervalId = setInterval(function() {
|
||||
websocketCalls.sendNewEvent({op: 'PING'});
|
||||
}, 10000);
|
||||
});
|
||||
websocketCalls.ws.onOpen(function() {
|
||||
console.log('Websocket created');
|
||||
$rootScope.$broadcast('setConnectedStatus', true);
|
||||
pingIntervalId = setInterval(function() {
|
||||
websocketCalls.sendNewEvent({op: 'PING'});
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
websocketCalls.sendNewEvent = function(data) {
|
||||
if ($rootScope.ticket !== undefined) {
|
||||
data.principal = $rootScope.ticket.principal;
|
||||
data.ticket = $rootScope.ticket.ticket;
|
||||
data.roles = $rootScope.ticket.roles;
|
||||
websocketCalls.sendNewEvent = function(data) {
|
||||
if ($rootScope.ticket !== undefined) {
|
||||
data.principal = $rootScope.ticket.principal;
|
||||
data.ticket = $rootScope.ticket.ticket;
|
||||
data.roles = $rootScope.ticket.roles;
|
||||
} else {
|
||||
data.principal = '';
|
||||
data.ticket = '';
|
||||
data.roles = '';
|
||||
}
|
||||
console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data);
|
||||
websocketCalls.ws.send(JSON.stringify(data));
|
||||
};
|
||||
|
||||
websocketCalls.isConnected = function() {
|
||||
return (websocketCalls.ws.socket.readyState === 1);
|
||||
};
|
||||
|
||||
websocketCalls.ws.onMessage(function(event) {
|
||||
var payload;
|
||||
if (event.data) {
|
||||
payload = angular.fromJson(event.data);
|
||||
}
|
||||
console.log('Receive << %o, %o', payload.op, payload);
|
||||
var op = payload.op;
|
||||
var data = payload.data;
|
||||
if (op === 'NOTE') {
|
||||
$rootScope.$broadcast('setNoteContent', data.note);
|
||||
} else if (op === 'NEW_NOTE') {
|
||||
$location.path('/notebook/' + data.note.id);
|
||||
} else if (op === 'NOTES_INFO') {
|
||||
$rootScope.$broadcast('setNoteMenu', data.notes);
|
||||
} else if (op === 'LIST_NOTE_JOBS') {
|
||||
$rootScope.$broadcast('setNoteJobs', data.noteJobs);
|
||||
} else if (op === 'LIST_UPDATE_NOTE_JOBS') {
|
||||
$rootScope.$broadcast('setUpdateNoteJobs', data.noteRunningJobs);
|
||||
} else if (op === 'AUTH_INFO') {
|
||||
var btn = [];
|
||||
if ($rootScope.ticket.roles === '[]') {
|
||||
btn = [{
|
||||
label: 'Close',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
data.principal = '';
|
||||
data.ticket = '';
|
||||
data.roles = '';
|
||||
btn = [{
|
||||
label: 'Login',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
angular.element('#loginModal').modal({
|
||||
show: 'true'
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: 'Cancel',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
$location.path('/');
|
||||
}
|
||||
}];
|
||||
}
|
||||
console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data);
|
||||
websocketCalls.ws.send(JSON.stringify(data));
|
||||
};
|
||||
|
||||
websocketCalls.isConnected = function() {
|
||||
return (websocketCalls.ws.socket.readyState === 1);
|
||||
};
|
||||
BootstrapDialog.show({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: 'Insufficient privileges',
|
||||
message: data.info.toString(),
|
||||
buttons: btn
|
||||
});
|
||||
|
||||
websocketCalls.ws.onMessage(function(event) {
|
||||
var payload;
|
||||
if (event.data) {
|
||||
payload = angular.fromJson(event.data);
|
||||
}
|
||||
console.log('Receive << %o, %o', payload.op, payload);
|
||||
var op = payload.op;
|
||||
var data = payload.data;
|
||||
if (op === 'NOTE') {
|
||||
$rootScope.$broadcast('setNoteContent', data.note);
|
||||
} else if (op === 'NEW_NOTE') {
|
||||
$location.path('/notebook/' + data.note.id);
|
||||
} else if (op === 'NOTES_INFO') {
|
||||
$rootScope.$broadcast('setNoteMenu', data.notes);
|
||||
} else if (op === 'LIST_NOTE_JOBS') {
|
||||
$rootScope.$broadcast('setNoteJobs', data.noteJobs);
|
||||
} else if (op === 'LIST_UPDATE_NOTE_JOBS') {
|
||||
$rootScope.$broadcast('setUpdateNoteJobs', data.noteRunningJobs);
|
||||
} else if (op === 'AUTH_INFO') {
|
||||
var btn = [];
|
||||
if ($rootScope.ticket.roles === '[]') {
|
||||
btn = [{
|
||||
label: 'Close',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
btn = [{
|
||||
label: 'Login',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
angular.element('#loginModal').modal({
|
||||
show: 'true'
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: 'Cancel',
|
||||
action: function(dialog) {
|
||||
dialog.close();
|
||||
$location.path('/');
|
||||
}
|
||||
}];
|
||||
}
|
||||
} else if (op === 'PARAGRAPH') {
|
||||
$rootScope.$broadcast('updateParagraph', data);
|
||||
} else if (op === 'PARAGRAPH_APPEND_OUTPUT') {
|
||||
$rootScope.$broadcast('appendParagraphOutput', data);
|
||||
} else if (op === 'PARAGRAPH_UPDATE_OUTPUT') {
|
||||
$rootScope.$broadcast('updateParagraphOutput', data);
|
||||
} else if (op === 'PROGRESS') {
|
||||
$rootScope.$broadcast('updateProgress', data);
|
||||
} else if (op === 'COMPLETION_LIST') {
|
||||
$rootScope.$broadcast('completionList', data);
|
||||
} else if (op === 'EDITOR_SETTING') {
|
||||
$rootScope.$broadcast('editorSetting', data);
|
||||
} else if (op === 'ANGULAR_OBJECT_UPDATE') {
|
||||
$rootScope.$broadcast('angularObjectUpdate', data);
|
||||
} else if (op === 'ANGULAR_OBJECT_REMOVE') {
|
||||
$rootScope.$broadcast('angularObjectRemove', data);
|
||||
} else if (op === 'APP_APPEND_OUTPUT') {
|
||||
$rootScope.$broadcast('appendAppOutput', data);
|
||||
} else if (op === 'APP_UPDATE_OUTPUT') {
|
||||
$rootScope.$broadcast('updateAppOutput', data);
|
||||
} else if (op === 'APP_LOAD') {
|
||||
$rootScope.$broadcast('appLoad', data);
|
||||
} else if (op === 'APP_STATUS_CHANGE') {
|
||||
$rootScope.$broadcast('appStatusChange', data);
|
||||
} else if (op === 'LIST_REVISION_HISTORY') {
|
||||
$rootScope.$broadcast('listRevisionHistory', data);
|
||||
} else if (op === 'NOTE_REVISION') {
|
||||
$rootScope.$broadcast('noteRevision', data);
|
||||
} else if (op === 'INTERPRETER_BINDINGS') {
|
||||
$rootScope.$broadcast('interpreterBindings', data);
|
||||
} else if (op === 'ERROR_INFO') {
|
||||
BootstrapDialog.show({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: 'Details',
|
||||
message: data.info.toString(),
|
||||
buttons: [{
|
||||
// close all the dialogs when there are error on running all paragraphs
|
||||
label: 'Close',
|
||||
action: function() {
|
||||
BootstrapDialog.closeAll();
|
||||
}
|
||||
}]
|
||||
});
|
||||
} else if (op === 'CONFIGURATIONS_INFO') {
|
||||
$rootScope.$broadcast('configurationsInfo', data);
|
||||
} else if (op === 'INTERPRETER_SETTINGS') {
|
||||
$rootScope.$broadcast('interpreterSettings', data);
|
||||
} else if (op === 'PARAGRAPH_ADDED') {
|
||||
$rootScope.$broadcast('addParagraph', data.paragraph, data.index);
|
||||
} else if (op === 'PARAGRAPH_REMOVED') {
|
||||
$rootScope.$broadcast('removeParagraph', data.id);
|
||||
} else if (op === 'PARAGRAPH_MOVED') {
|
||||
$rootScope.$broadcast('moveParagraph', data.id, data.index);
|
||||
} else if (op === 'NOTE_UPDATED') {
|
||||
$rootScope.$broadcast('updateNote', data.name, data.config, data.info);
|
||||
} else if (op === 'SET_NOTE_REVISION') {
|
||||
$rootScope.$broadcast('setNoteRevisionResult', data);
|
||||
}
|
||||
});
|
||||
|
||||
BootstrapDialog.show({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: 'Insufficient privileges',
|
||||
message: data.info.toString(),
|
||||
buttons: btn
|
||||
});
|
||||
websocketCalls.ws.onError(function(event) {
|
||||
console.log('error message: ', event);
|
||||
$rootScope.$broadcast('setConnectedStatus', false);
|
||||
});
|
||||
|
||||
} else if (op === 'PARAGRAPH') {
|
||||
$rootScope.$broadcast('updateParagraph', data);
|
||||
} else if (op === 'PARAGRAPH_APPEND_OUTPUT') {
|
||||
$rootScope.$broadcast('appendParagraphOutput', data);
|
||||
} else if (op === 'PARAGRAPH_UPDATE_OUTPUT') {
|
||||
$rootScope.$broadcast('updateParagraphOutput', data);
|
||||
} else if (op === 'PROGRESS') {
|
||||
$rootScope.$broadcast('updateProgress', data);
|
||||
} else if (op === 'COMPLETION_LIST') {
|
||||
$rootScope.$broadcast('completionList', data);
|
||||
} else if (op === 'EDITOR_SETTING') {
|
||||
$rootScope.$broadcast('editorSetting', data);
|
||||
} else if (op === 'ANGULAR_OBJECT_UPDATE') {
|
||||
$rootScope.$broadcast('angularObjectUpdate', data);
|
||||
} else if (op === 'ANGULAR_OBJECT_REMOVE') {
|
||||
$rootScope.$broadcast('angularObjectRemove', data);
|
||||
} else if (op === 'APP_APPEND_OUTPUT') {
|
||||
$rootScope.$broadcast('appendAppOutput', data);
|
||||
} else if (op === 'APP_UPDATE_OUTPUT') {
|
||||
$rootScope.$broadcast('updateAppOutput', data);
|
||||
} else if (op === 'APP_LOAD') {
|
||||
$rootScope.$broadcast('appLoad', data);
|
||||
} else if (op === 'APP_STATUS_CHANGE') {
|
||||
$rootScope.$broadcast('appStatusChange', data);
|
||||
} else if (op === 'LIST_REVISION_HISTORY') {
|
||||
$rootScope.$broadcast('listRevisionHistory', data);
|
||||
} else if (op === 'NOTE_REVISION') {
|
||||
$rootScope.$broadcast('noteRevision', data);
|
||||
} else if (op === 'INTERPRETER_BINDINGS') {
|
||||
$rootScope.$broadcast('interpreterBindings', data);
|
||||
} else if (op === 'ERROR_INFO') {
|
||||
BootstrapDialog.show({
|
||||
closable: false,
|
||||
closeByBackdrop: false,
|
||||
closeByKeyboard: false,
|
||||
title: 'Details',
|
||||
message: data.info.toString(),
|
||||
buttons: [{
|
||||
// close all the dialogs when there are error on running all paragraphs
|
||||
label: 'Close',
|
||||
action: function() {
|
||||
BootstrapDialog.closeAll();
|
||||
}
|
||||
}]
|
||||
});
|
||||
} else if (op === 'CONFIGURATIONS_INFO') {
|
||||
$rootScope.$broadcast('configurationsInfo', data);
|
||||
} else if (op === 'INTERPRETER_SETTINGS') {
|
||||
$rootScope.$broadcast('interpreterSettings', data);
|
||||
} else if (op === 'PARAGRAPH_ADDED') {
|
||||
$rootScope.$broadcast('addParagraph', data.paragraph, data.index);
|
||||
} else if (op === 'PARAGRAPH_REMOVED') {
|
||||
$rootScope.$broadcast('removeParagraph', data.id);
|
||||
} else if (op === 'PARAGRAPH_MOVED') {
|
||||
$rootScope.$broadcast('moveParagraph', data.id, data.index);
|
||||
} else if (op === 'NOTE_UPDATED') {
|
||||
$rootScope.$broadcast('updateNote', data.name, data.config, data.info);
|
||||
} else if (op === 'SET_NOTE_REVISION') {
|
||||
$rootScope.$broadcast('setNoteRevisionResult', data);
|
||||
}
|
||||
});
|
||||
websocketCalls.ws.onClose(function(event) {
|
||||
console.log('close message: ', event);
|
||||
if (pingIntervalId !== undefined) {
|
||||
clearInterval(pingIntervalId);
|
||||
pingIntervalId = undefined;
|
||||
}
|
||||
$rootScope.$broadcast('setConnectedStatus', false);
|
||||
});
|
||||
|
||||
websocketCalls.ws.onError(function(event) {
|
||||
console.log('error message: ', event);
|
||||
$rootScope.$broadcast('setConnectedStatus', false);
|
||||
});
|
||||
return websocketCalls;
|
||||
}
|
||||
|
||||
websocketCalls.ws.onClose(function(event) {
|
||||
console.log('close message: ', event);
|
||||
if (pingIntervalId !== undefined) {
|
||||
clearInterval(pingIntervalId);
|
||||
pingIntervalId = undefined;
|
||||
}
|
||||
$rootScope.$broadcast('setConnectedStatus', false);
|
||||
});
|
||||
|
||||
return websocketCalls;
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -11,298 +11,306 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
angular.module('zeppelinWebApp').service('websocketMsgSrv', websocketMsgSrv);
|
||||
angular.module('zeppelinWebApp').service('websocketMsgSrv', websocketMsgSrv);
|
||||
|
||||
websocketMsgSrv.$inject = ['$rootScope', 'websocketEvents'];
|
||||
websocketMsgSrv.$inject = ['$rootScope', 'websocketEvents'];
|
||||
|
||||
function websocketMsgSrv($rootScope, websocketEvents) {
|
||||
return {
|
||||
function websocketMsgSrv($rootScope, websocketEvents) {
|
||||
return {
|
||||
|
||||
getHomeNote: function() {
|
||||
websocketEvents.sendNewEvent({op: 'GET_HOME_NOTE'});
|
||||
},
|
||||
getHomeNote: function() {
|
||||
websocketEvents.sendNewEvent({op: 'GET_HOME_NOTE'});
|
||||
},
|
||||
|
||||
createNotebook: function(noteName, defaultInterpreterId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'NEW_NOTE',
|
||||
data: {
|
||||
name: noteName,
|
||||
defaultInterpreterId: defaultInterpreterId
|
||||
}
|
||||
});
|
||||
},
|
||||
createNotebook: function(noteName, defaultInterpreterId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'NEW_NOTE',
|
||||
data: {
|
||||
name: noteName,
|
||||
defaultInterpreterId: defaultInterpreterId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
moveNoteToTrash: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_NOTE_TO_TRASH', data: {id: noteId}});
|
||||
},
|
||||
moveNoteToTrash: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_NOTE_TO_TRASH', data: {id: noteId}});
|
||||
},
|
||||
|
||||
moveFolderToTrash: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_FOLDER_TO_TRASH', data: {id: folderId}});
|
||||
},
|
||||
moveFolderToTrash: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_FOLDER_TO_TRASH', data: {id: folderId}});
|
||||
},
|
||||
|
||||
restoreNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_NOTE', data: {id: noteId}});
|
||||
},
|
||||
restoreNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_NOTE', data: {id: noteId}});
|
||||
},
|
||||
|
||||
restoreFolder: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_FOLDER', data: {id: folderId}});
|
||||
},
|
||||
restoreFolder: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_FOLDER', data: {id: folderId}});
|
||||
},
|
||||
|
||||
restoreAll: function() {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_ALL'});
|
||||
},
|
||||
restoreAll: function() {
|
||||
websocketEvents.sendNewEvent({op: 'RESTORE_ALL'});
|
||||
},
|
||||
|
||||
deleteNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'DEL_NOTE', data: {id: noteId}});
|
||||
},
|
||||
deleteNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'DEL_NOTE', data: {id: noteId}});
|
||||
},
|
||||
|
||||
removeFolder: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'REMOVE_FOLDER', data: {id: folderId}});
|
||||
},
|
||||
removeFolder: function(folderId) {
|
||||
websocketEvents.sendNewEvent({op: 'REMOVE_FOLDER', data: {id: folderId}});
|
||||
},
|
||||
|
||||
emptyTrash: function() {
|
||||
websocketEvents.sendNewEvent({op: 'EMPTY_TRASH'});
|
||||
},
|
||||
emptyTrash: function() {
|
||||
websocketEvents.sendNewEvent({op: 'EMPTY_TRASH'});
|
||||
},
|
||||
|
||||
cloneNote: function(noteIdToClone, newNoteName) {
|
||||
websocketEvents.sendNewEvent({op: 'CLONE_NOTE', data: {id: noteIdToClone, name: newNoteName}});
|
||||
},
|
||||
cloneNote: function(noteIdToClone, newNoteName) {
|
||||
websocketEvents.sendNewEvent({op: 'CLONE_NOTE', data: {id: noteIdToClone, name: newNoteName}});
|
||||
},
|
||||
|
||||
getNoteList: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_NOTES'});
|
||||
},
|
||||
getNoteList: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_NOTES'});
|
||||
},
|
||||
|
||||
reloadAllNotesFromRepo: function() {
|
||||
websocketEvents.sendNewEvent({op: 'RELOAD_NOTES_FROM_REPO'});
|
||||
},
|
||||
reloadAllNotesFromRepo: function() {
|
||||
websocketEvents.sendNewEvent({op: 'RELOAD_NOTES_FROM_REPO'});
|
||||
},
|
||||
|
||||
getNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'GET_NOTE', data: {id: noteId}});
|
||||
},
|
||||
getNote: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'GET_NOTE', data: {id: noteId}});
|
||||
},
|
||||
|
||||
updateNote: function(noteId, noteName, noteConfig) {
|
||||
websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config: noteConfig}});
|
||||
},
|
||||
updateNote: function(noteId, noteName, noteConfig) {
|
||||
websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config: noteConfig}});
|
||||
},
|
||||
|
||||
updatePersonalizedMode: function(noteId, modeValue) {
|
||||
websocketEvents.sendNewEvent({op: 'UPDATE_PERSONALIZED_MODE', data: {id: noteId, personalized: modeValue}});
|
||||
},
|
||||
updatePersonalizedMode: function(noteId, modeValue) {
|
||||
websocketEvents.sendNewEvent({op: 'UPDATE_PERSONALIZED_MODE', data: {id: noteId, personalized: modeValue}});
|
||||
},
|
||||
|
||||
renameNote: function(noteId, noteName) {
|
||||
websocketEvents.sendNewEvent({op: 'NOTE_RENAME', data: {id: noteId, name: noteName}});
|
||||
},
|
||||
renameNote: function(noteId, noteName) {
|
||||
websocketEvents.sendNewEvent({op: 'NOTE_RENAME', data: {id: noteId, name: noteName}});
|
||||
},
|
||||
|
||||
renameFolder: function(folderId, folderName) {
|
||||
websocketEvents.sendNewEvent({op: 'FOLDER_RENAME', data: {id: folderId, name: folderName}});
|
||||
},
|
||||
renameFolder: function(folderId, folderName) {
|
||||
websocketEvents.sendNewEvent({op: 'FOLDER_RENAME', data: {id: folderId, name: folderName}});
|
||||
},
|
||||
|
||||
moveParagraph: function(paragraphId, newIndex) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_PARAGRAPH', data: {id: paragraphId, index: newIndex}});
|
||||
},
|
||||
moveParagraph: function(paragraphId, newIndex) {
|
||||
websocketEvents.sendNewEvent({op: 'MOVE_PARAGRAPH', data: {id: paragraphId, index: newIndex}});
|
||||
},
|
||||
|
||||
insertParagraph: function(newIndex) {
|
||||
websocketEvents.sendNewEvent({op: 'INSERT_PARAGRAPH', data: {index: newIndex}});
|
||||
},
|
||||
insertParagraph: function(newIndex) {
|
||||
websocketEvents.sendNewEvent({op: 'INSERT_PARAGRAPH', data: {index: newIndex}});
|
||||
},
|
||||
|
||||
copyParagraph: function(newIndex, paragraphTitle, paragraphData,
|
||||
paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COPY_PARAGRAPH',
|
||||
data: {
|
||||
index: newIndex,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
copyParagraph: function(newIndex, paragraphTitle, paragraphData,
|
||||
paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COPY_PARAGRAPH',
|
||||
data: {
|
||||
index: newIndex,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateAngularObject: function(noteId, paragraphId, name, value, interpreterGroupId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_UPDATED',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
paragraphId: paragraphId,
|
||||
name: name,
|
||||
value: value,
|
||||
interpreterGroupId: interpreterGroupId
|
||||
}
|
||||
});
|
||||
},
|
||||
updateAngularObject: function(noteId, paragraphId, name, value, interpreterGroupId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_UPDATED',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
paragraphId: paragraphId,
|
||||
name: name,
|
||||
value: value,
|
||||
interpreterGroupId: interpreterGroupId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clientBindAngularObject: function(noteId, name, value, paragraphId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_CLIENT_BIND',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
name: name,
|
||||
value: value,
|
||||
paragraphId: paragraphId
|
||||
}
|
||||
});
|
||||
},
|
||||
clientBindAngularObject: function(noteId, name, value, paragraphId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_CLIENT_BIND',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
name: name,
|
||||
value: value,
|
||||
paragraphId: paragraphId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clientUnbindAngularObject: function(noteId, name, paragraphId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_CLIENT_UNBIND',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
name: name,
|
||||
paragraphId: paragraphId
|
||||
}
|
||||
});
|
||||
},
|
||||
clientUnbindAngularObject: function(noteId, name, paragraphId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'ANGULAR_OBJECT_CLIENT_UNBIND',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
name: name,
|
||||
paragraphId: paragraphId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancelParagraphRun: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'CANCEL_PARAGRAPH', data: {id: paragraphId}});
|
||||
},
|
||||
cancelParagraphRun: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'CANCEL_PARAGRAPH', data: {id: paragraphId}});
|
||||
},
|
||||
|
||||
runParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'RUN_PARAGRAPH',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
runParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'RUN_PARAGRAPH',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeParagraph: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}});
|
||||
},
|
||||
runAllParagraphs: function(noteId, paragraphs) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'RUN_ALL_PARAGRAPHS',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
paragraphs: JSON.stringify(paragraphs)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
clearParagraphOutput: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_OUTPUT', data: {id: paragraphId}});
|
||||
},
|
||||
removeParagraph: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}});
|
||||
},
|
||||
|
||||
clearAllParagraphOutput: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_ALL_OUTPUT', data: {id: noteId}});
|
||||
},
|
||||
clearParagraphOutput: function(paragraphId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_OUTPUT', data: {id: paragraphId}});
|
||||
},
|
||||
|
||||
completion: function(paragraphId, buf, cursor) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COMPLETION',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
buf: buf,
|
||||
cursor: cursor
|
||||
}
|
||||
});
|
||||
},
|
||||
clearAllParagraphOutput: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_ALL_OUTPUT', data: {id: noteId}});
|
||||
},
|
||||
|
||||
commitParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COMMIT_PARAGRAPH',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
completion: function(paragraphId, buf, cursor) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COMPLETION',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
buf: buf,
|
||||
cursor: cursor
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
importNote: function(note) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'IMPORT_NOTE',
|
||||
data: {
|
||||
note: note
|
||||
}
|
||||
});
|
||||
},
|
||||
commitParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'COMMIT_PARAGRAPH',
|
||||
data: {
|
||||
id: paragraphId,
|
||||
title: paragraphTitle,
|
||||
paragraph: paragraphData,
|
||||
config: paragraphConfig,
|
||||
params: paragraphParams
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
checkpointNote: function(noteId, commitMessage) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'CHECKPOINT_NOTE',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
commitMessage: commitMessage
|
||||
}
|
||||
});
|
||||
},
|
||||
importNote: function(note) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'IMPORT_NOTE',
|
||||
data: {
|
||||
note: note
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setNoteRevision: function(noteId, revisionId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'SET_NOTE_REVISION',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
revisionId: revisionId
|
||||
}
|
||||
});
|
||||
},
|
||||
checkpointNote: function(noteId, commitMessage) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'CHECKPOINT_NOTE',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
commitMessage: commitMessage
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
listRevisionHistory: function(noteId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'LIST_REVISION_HISTORY',
|
||||
data: {
|
||||
noteId: noteId
|
||||
}
|
||||
});
|
||||
},
|
||||
setNoteRevision: function(noteId, revisionId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'SET_NOTE_REVISION',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
revisionId: revisionId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getNoteByRevision: function(noteId, revisionId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'NOTE_REVISION',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
revisionId: revisionId
|
||||
}
|
||||
});
|
||||
},
|
||||
listRevisionHistory: function(noteId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'LIST_REVISION_HISTORY',
|
||||
data: {
|
||||
noteId: noteId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getEditorSetting: function(paragraphId, replName) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'EDITOR_SETTING',
|
||||
data: {
|
||||
paragraphId: paragraphId,
|
||||
magic: replName
|
||||
}
|
||||
});
|
||||
},
|
||||
getNoteByRevision: function(noteId, revisionId) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'NOTE_REVISION',
|
||||
data: {
|
||||
noteId: noteId,
|
||||
revisionId: revisionId
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
isConnected: function() {
|
||||
return websocketEvents.isConnected();
|
||||
},
|
||||
getEditorSetting: function(paragraphId, replName) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'EDITOR_SETTING',
|
||||
data: {
|
||||
paragraphId: paragraphId,
|
||||
magic: replName
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getNoteJobsList: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_NOTE_JOBS'});
|
||||
},
|
||||
isConnected: function() {
|
||||
return websocketEvents.isConnected();
|
||||
},
|
||||
|
||||
getUpdateNoteJobsList: function(lastUpdateServerUnixTime) {
|
||||
websocketEvents.sendNewEvent(
|
||||
{op: 'LIST_UPDATE_NOTE_JOBS', data: {lastUpdateUnixTime: lastUpdateServerUnixTime * 1}}
|
||||
);
|
||||
},
|
||||
getNoteJobsList: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_NOTE_JOBS'});
|
||||
},
|
||||
|
||||
unsubscribeJobManager: function() {
|
||||
websocketEvents.sendNewEvent({op: 'UNSUBSCRIBE_UPDATE_NOTE_JOBS'});
|
||||
},
|
||||
getUpdateNoteJobsList: function(lastUpdateServerUnixTime) {
|
||||
websocketEvents.sendNewEvent(
|
||||
{op: 'LIST_UPDATE_NOTE_JOBS', data: {lastUpdateUnixTime: lastUpdateServerUnixTime * 1}}
|
||||
);
|
||||
},
|
||||
|
||||
getInterpreterBindings: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_BINDINGS', data: {noteId: noteId}});
|
||||
},
|
||||
unsubscribeJobManager: function() {
|
||||
websocketEvents.sendNewEvent({op: 'UNSUBSCRIBE_UPDATE_NOTE_JOBS'});
|
||||
},
|
||||
|
||||
saveInterpreterBindings: function(noteId, selectedSettingIds) {
|
||||
websocketEvents.sendNewEvent({op: 'SAVE_INTERPRETER_BINDINGS',
|
||||
data: {noteId: noteId, selectedSettingIds: selectedSettingIds}});
|
||||
},
|
||||
getInterpreterBindings: function(noteId) {
|
||||
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_BINDINGS', data: {noteId: noteId}});
|
||||
},
|
||||
|
||||
listConfigurations: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_CONFIGURATIONS'});
|
||||
},
|
||||
saveInterpreterBindings: function(noteId, selectedSettingIds) {
|
||||
websocketEvents.sendNewEvent({op: 'SAVE_INTERPRETER_BINDINGS',
|
||||
data: {noteId: noteId, selectedSettingIds: selectedSettingIds}});
|
||||
},
|
||||
|
||||
getInterpreterSettings: function() {
|
||||
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_SETTINGS'});
|
||||
}
|
||||
listConfigurations: function() {
|
||||
websocketEvents.sendNewEvent({op: 'LIST_CONFIGURATIONS'});
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
getInterpreterSettings: function() {
|
||||
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_SETTINGS'});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ limitations under the License.
|
|||
<link rel="stylesheet" href="app/search/search.css" />
|
||||
<link rel="stylesheet" href="app/notebook/notebook.css" />
|
||||
<link rel="stylesheet" href="app/notebook/paragraph/paragraph.css" />
|
||||
<link rel="stylesheet" href="app/notebook/paragraph/result/result.css" />
|
||||
<link rel="stylesheet" href="app/jobmanager/jobmanager.css" />
|
||||
<link rel="stylesheet" href="app/jobmanager/jobs/job.css" />
|
||||
<link rel="stylesheet" href="app/interpreter/interpreter.css" />
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ describe('Controller: NotebookCtrl', function() {
|
|||
scope.note = noteMock;
|
||||
});
|
||||
|
||||
var functions = ['getCronOptionNameFromValue', 'removeNote', 'runNote', 'saveNote', 'toggleAllEditor',
|
||||
var functions = ['getCronOptionNameFromValue', 'removeNote', 'runAllParagraphs', 'saveNote', 'toggleAllEditor',
|
||||
'showAllEditor', 'hideAllEditor', 'toggleAllTable', 'hideAllTable', 'showAllTable', 'isNoteRunning',
|
||||
'killSaveTimer', 'startSaveTimer', 'setLookAndFeel', 'setCronScheduler', 'setConfig', 'updateNoteName',
|
||||
'openSetting', 'closeSetting', 'saveSetting', 'toggleSetting'];
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ module.exports = function makeWebpackConfig () {
|
|||
|
||||
// Output path from the view of the page
|
||||
// Uses webpack-dev-server in development
|
||||
publicPath: isProd ? '/' : 'http://localhost:9000/',
|
||||
publicPath: isProd ? '' : 'http://localhost:9000/',
|
||||
|
||||
// Filename for entry points
|
||||
// Only adds hash in build mode
|
||||
|
|
|
|||
|
|
@ -369,6 +369,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
return getString(ConfVars.ZEPPELIN_NOTEBOOK_S3_KMS_KEY_ID);
|
||||
}
|
||||
|
||||
public String getS3KMSKeyRegion() {
|
||||
return getString(ConfVars.ZEPPELIN_NOTEBOOK_S3_KMS_KEY_REGION);
|
||||
}
|
||||
|
||||
public String getS3EncryptionMaterialsProviderClass() {
|
||||
return getString(ConfVars.ZEPPELIN_NOTEBOOK_S3_EMP);
|
||||
}
|
||||
|
|
@ -579,6 +583,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
ZEPPELIN_NOTEBOOK_S3_USER("zeppelin.notebook.s3.user", "user"),
|
||||
ZEPPELIN_NOTEBOOK_S3_EMP("zeppelin.notebook.s3.encryptionMaterialsProvider", null),
|
||||
ZEPPELIN_NOTEBOOK_S3_KMS_KEY_ID("zeppelin.notebook.s3.kmsKeyID", null),
|
||||
ZEPPELIN_NOTEBOOK_S3_KMS_KEY_REGION("zeppelin.notebook.s3.kmsKeyRegion", null),
|
||||
ZEPPELIN_NOTEBOOK_AZURE_CONNECTION_STRING("zeppelin.notebook.azure.connectionString", null),
|
||||
ZEPPELIN_NOTEBOOK_AZURE_SHARE("zeppelin.notebook.azure.share", "zeppelin"),
|
||||
ZEPPELIN_NOTEBOOK_AZURE_USER("zeppelin.notebook.azure.user", "user"),
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ import org.apache.zeppelin.display.AngularObjectRegistry;
|
|||
import org.apache.zeppelin.display.AngularObjectRegistryListener;
|
||||
import org.apache.zeppelin.helium.ApplicationEventListener;
|
||||
import org.apache.zeppelin.interpreter.Interpreter.RegisteredInterpreter;
|
||||
import org.apache.zeppelin.interpreter.dev.DevInterpreter;
|
||||
import org.apache.zeppelin.interpreter.dev.ZeppelinDevServer;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreter;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcessListener;
|
||||
|
|
@ -1372,11 +1370,6 @@ public class InterpreterFactory implements InterpreterGroupFactory {
|
|||
}
|
||||
}
|
||||
|
||||
// dev interpreter
|
||||
if (DevInterpreter.isInterpreterName(replName)) {
|
||||
return getDevInterpreter();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -1453,24 +1446,4 @@ public class InterpreterFactory implements InterpreterGroupFactory {
|
|||
}
|
||||
return editor;
|
||||
}
|
||||
|
||||
private Interpreter getDevInterpreter() {
|
||||
if (devInterpreter == null) {
|
||||
InterpreterOption option = new InterpreterOption();
|
||||
option.setRemote(true);
|
||||
|
||||
InterpreterGroup interpreterGroup = createInterpreterGroup("dev", option);
|
||||
|
||||
devInterpreter = connectToRemoteRepl("dev", DevInterpreter.class.getName(), "localhost",
|
||||
ZeppelinDevServer.DEFAULT_TEST_INTERPRETER_PORT, new Properties(), "dev", "anonymous",
|
||||
false);
|
||||
|
||||
LinkedList<Interpreter> intpList = new LinkedList<>();
|
||||
intpList.add(devInterpreter);
|
||||
interpreterGroup.put("dev", intpList);
|
||||
|
||||
devInterpreter.setInterpreterGroup(interpreterGroup);
|
||||
}
|
||||
return devInterpreter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.Map;
|
|||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
|
||||
import org.apache.zeppelin.notebook.Note;
|
||||
|
|
@ -48,12 +49,15 @@ import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
|
|||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3Client;
|
||||
import com.amazonaws.services.s3.AmazonS3EncryptionClient;
|
||||
import com.amazonaws.services.s3.model.CryptoConfiguration;
|
||||
import com.amazonaws.services.s3.model.EncryptionMaterialsProvider;
|
||||
import com.amazonaws.services.s3.model.GetObjectRequest;
|
||||
import com.amazonaws.services.s3.model.KMSEncryptionMaterialsProvider;
|
||||
import com.amazonaws.services.s3.model.ListObjectsRequest;
|
||||
import com.amazonaws.services.s3.model.ObjectListing;
|
||||
import com.amazonaws.services.s3.model.PutObjectRequest;
|
||||
import com.amazonaws.regions.Region;
|
||||
import com.amazonaws.regions.Regions;
|
||||
import com.amazonaws.services.s3.model.S3Object;
|
||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||
import com.google.gson.Gson;
|
||||
|
|
@ -91,13 +95,24 @@ public class S3NotebookRepo implements NotebookRepo {
|
|||
|
||||
// always use the default provider chain
|
||||
AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain();
|
||||
CryptoConfiguration cryptoConf = null;
|
||||
String keyRegion = conf.getS3KMSKeyRegion();
|
||||
|
||||
if (StringUtils.isNotBlank(keyRegion)) {
|
||||
cryptoConf = new CryptoConfiguration();
|
||||
cryptoConf.setAwsKmsRegion(Region.getRegion(Regions.fromName(keyRegion)));
|
||||
}
|
||||
|
||||
// see if we should be encrypting data in S3
|
||||
String kmsKeyID = conf.getS3KMSKeyID();
|
||||
if (kmsKeyID != null) {
|
||||
// use the AWS KMS to encrypt data
|
||||
KMSEncryptionMaterialsProvider emp = new KMSEncryptionMaterialsProvider(kmsKeyID);
|
||||
this.s3client = new AmazonS3EncryptionClient(credentialsProvider, emp);
|
||||
if (cryptoConf != null) {
|
||||
this.s3client = new AmazonS3EncryptionClient(credentialsProvider, emp, cryptoConf);
|
||||
} else {
|
||||
this.s3client = new AmazonS3EncryptionClient(credentialsProvider, emp);
|
||||
}
|
||||
}
|
||||
else if (conf.getS3EncryptionMaterialsProviderClass() != null) {
|
||||
// use a custom encryption materials provider class
|
||||
|
|
|
|||
|
|
@ -171,7 +171,8 @@ public class Message {
|
|||
PARAGRAPH_ADDED, // [s-c] paragraph is added
|
||||
PARAGRAPH_REMOVED, // [s-c] paragraph deleted
|
||||
PARAGRAPH_MOVED, // [s-c] paragraph moved
|
||||
NOTE_UPDATED // [s-c] paragraph updated(name, config)
|
||||
NOTE_UPDATED, // [s-c] paragraph updated(name, config)
|
||||
RUN_ALL_PARAGRAPHS // [c-s] run all paragraphs
|
||||
}
|
||||
|
||||
public static final Message EMPTY = new Message(null);
|
||||
|
|
|
|||
Loading…
Reference in a new issue