diff --git a/.gitignore b/.gitignore index 93962a16b7e..1358a425246 100644 --- a/.gitignore +++ b/.gitignore @@ -12,26 +12,30 @@ conf/keystore conf/truststore conf/interpreter.json +# other generated files +spark/dependency-reduced-pom.xml + #webapp zeppelin-web/node_modules zeppelin-web/dist zeppelin-web/.tmp zeppelin-web/.sass-cache zeppelin-web/bower_components -zeppelin-web/src **nbproject/ **node/ -logs/ -run/ -metastore_db/ -*.log -jobs/ -zan-repo/ -drivers/ -warehouse/ -notebook/ -local-repo/ + +# project level +/logs/ +/run/ +/metastore_db/ +/*.log +/jobs/ +/zan-repo/ +/drivers/ +/warehouse/ +/notebook/ +/local-repo/ **/sessions/ **/data/ diff --git a/bin/common.sh b/bin/common.sh index 8087e9d9be8..7aab870af14 100644 --- a/bin/common.sh +++ b/bin/common.sh @@ -45,8 +45,8 @@ if [[ -z "$ZEPPELIN_PID_DIR" ]]; then fi if [[ -z "${ZEPPELIN_WAR}" ]]; then - if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/src/main/webapp" ]]; then - export ZEPPELIN_WAR="${ZEPPELIN_HOME}/zeppelin-web/src/main/webapp" + if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/dist" ]]; then + export ZEPPELIN_WAR="${ZEPPELIN_HOME}/zeppelin-web/dist" else export ZEPPELIN_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web*.war") fi diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/AppScriptServlet.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/AppScriptServlet.java index 8c8f9a77f3a..7a314614faf 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/AppScriptServlet.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/AppScriptServlet.java @@ -41,7 +41,7 @@ public class AppScriptServlet extends DefaultServlet { private static Set scriptPaths = new HashSet( Arrays.asList( "/scripts/scripts.js", - "/scripts/app.js" + "/components/baseUrl/baseUrl.js" ) ); @@ -77,14 +77,16 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) script.append(new String(buffer, 0, numRead, "UTF-8")); } - // Replace the string "function getPort(){...}" to return - // the proper value - int startIndex = script.indexOf("function getPort()"); - int endIndex = script.indexOf("}", startIndex); + // Replace the getPort function to return the proper value + String startReplaceString = "/* @preserve AppScriptServlet - getPort */"; + String endReplaceString = "/* @preserve AppScriptServlet - close */"; + + int startIndex = script.indexOf(startReplaceString); + int endIndex = script.indexOf(endReplaceString, startIndex); if (startIndex >= 0 && endIndex >= 0) { - String replaceString = "function getPort(){return " + websocketPort + "}"; - script.replace(startIndex, endIndex + 1, replaceString); + String replaceString = "this.getPort=function(){return " + websocketPort + "};"; + script.replace(startIndex, endIndex + endReplaceString.length(), replaceString); } response.getWriter().println(script.toString()); diff --git a/zeppelin-web/.jshintrc b/zeppelin-web/.jshintrc index 40377ba25e5..008037e9267 100644 --- a/zeppelin-web/.jshintrc +++ b/zeppelin-web/.jshintrc @@ -12,9 +12,10 @@ "newcap": true, "noarg": true, "quotmark": "single", + "shadow": "inner", "regexp": true, "undef": true, - "unused": true, + "unused": "vars", "strict": true, "trailing": true, "smarttabs": true, diff --git a/zeppelin-web/CONTRIBUTING.md b/zeppelin-web/CONTRIBUTING.md new file mode 100644 index 00000000000..6873b0f8f97 --- /dev/null +++ b/zeppelin-web/CONTRIBUTING.md @@ -0,0 +1,118 @@ +# Contributing to Zeppelin-Web + +## Technologies + +Zeppelin WebApplication is using **AngularJS** as main Framework, and **Grunt** and **Bower** as helpers. + +So you might want to get familiar with it. +[Here is a good start](http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/) +(There is obviously plenty more ressources to learn) + +## Coding style + +* We follow mainly the [Google Javascript Guide](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) +* We use a 2 spaces indentation +* We use single quotes + +But don't worry, JSHint will make you remember it for the most part. + +There is also a rule of **No JQuery except in directives**, If you want to include a library, +please search for its **angularJS** directive first and if it doesn't exist, make one :) + +## Folder Structure & Code Organization + +* `src` folder: Contains the Source code for Zeppelin WebApplication +* `dist` folder: Contains the compiled code after using **grunt build** + +### Src and Code Organization + +The `src` folder is organized as such: + +
+ src/
+ ├──  app/
+ │   ├──  name/
+ │   │    ├──  name.controller.js
+ |   |    ├──  name.html
+ |   |    ├──  subComponent1/
+ |   |    |    ├──  subComponent1.html
+ |   |    |    ├──  subComponent1.css
+ │   |    |    └──  subComponent1.controller.js
+ │   │    └──  name.css
+ │   └──  app.js
+ ├──  assets/
+ │   ├──  images/
+ │   └──  styles/
+ |        ├──  looknfeel/
+ │        └──  printMode.css
+ ├──  components/
+ │   ├──  component1/
+ |   |    ├──  component1.html
+ │   |    └──  component1.controller.js
+ │   └──  component2/
+ ├──  fonts/
+ |    ├──  *.{eot,svg,ttf,woff,otf}
+ │    └──  *.css
+ ├──  favico.ico
+ ├──  index.html
+ └──  404.html
+
+ +The code is now organized in a component type of architecture, where everything is logically grouped. + +#### File type name convention + +In order to understand what is contained inside the .js files without opening it, we use some name conventions: +* .controller.js +* .directive.js +* .service.js + +### Component Architecture + +When we talk about Component architecture, we think about grouping files together in a logical way. + +A component can then be made of multiple files like `.html`, `.css` or any other file type mentioned above. + +Related components can be grouped as sub-component as long as they are used in that component only. + + +#### App folder + +Contains the application `app.js` and page related components. +* Home Page +* Interpreter Page +* Notebook Page +etc... + +The only resctiction being that a component in the `app` folder is **not used anywhere else** + +#### Components folder + +The `components` folder is here to contains any reusable component (used more than once) + +### Fonts + +Fonts files and their css are mixed together in the `fonts` folder + +## Compiling and using dev mode + +As we do not use yeoman to generate controllers or other type of files with this new structure, +we need to do some includes manually in `index.html` in order to use dev mode and compile correctly. + +* Non-bower `.js` files needs to be injected between the tag `` +* Css files needs to be injected between the tag `` + +## Add plugins with Bower +``` +bower install --save +``` +The file index.html will automatically update with the new bower_component + +
+ +**Example**: `./bower install angular-nvd3` + +You should find that line in the index.html file +``` + +```` diff --git a/zeppelin-web/Gruntfile.js b/zeppelin-web/Gruntfile.js index d544ba4c760..dc2a33e50fd 100644 --- a/zeppelin-web/Gruntfile.js +++ b/zeppelin-web/Gruntfile.js @@ -34,8 +34,8 @@ module.exports = function (grunt) { // Configurable paths for the application var appConfig = { - app: require('./bower.json').appPath || 'app', - dist: 'src/main/webapp' + app: require('./bower.json').appPath || 'src', + dist: 'dist' }; // Define the configuration for all the tasks @@ -63,7 +63,10 @@ module.exports = function (grunt) { tasks: ['wiredep'] }, js: { - files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], + files: [ + '<%= yeoman.app %>/app/**/*.js', + '<%= yeoman.app %>/components/**/*.js' + ], tasks: ['newer:jshint:all'], options: { livereload: '<%= connect.options.livereload %>' @@ -74,7 +77,12 @@ module.exports = function (grunt) { tasks: ['newer:jshint:test', 'karma'] }, styles: { - files: ['<%= yeoman.app %>/styles/{,*/}*.css'], + files: [ + '<%= yeoman.app %>/app/**/*.css', + '<%= yeoman.app %>/components/**/*.css', + '<%= yeoman.app %>/assets/styles/**/*.css', + '<%= yeoman.app %>/fonts/**/*.css' + ], tasks: ['newer:copy:styles', 'autoprefixer'] }, gruntfile: { @@ -85,9 +93,11 @@ module.exports = function (grunt) { livereload: '<%= connect.options.livereload %>' }, files: [ - '<%= yeoman.app %>/{,*/}*.html', + '<%= yeoman.app %>/app/**/*.html', + '<%= yeoman.app %>/*.html', + '<%= yeoman.app %>/components/**/*.html', '.tmp/styles/{,*/}*.css', - '<%= yeoman.app %>/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + '<%= yeoman.app %>/assets/images/**/*.{png,jpg,jpeg,gif,webp,svg}' ] } }, @@ -148,7 +158,8 @@ module.exports = function (grunt) { all: { src: [ 'Gruntfile.js', - '<%= yeoman.app %>/scripts/{,*/}*.js' + '<%= yeoman.app %>/app/**/*.js', + '<%= yeoman.app %>/components/**/*.js' ] }, test: { @@ -199,18 +210,6 @@ module.exports = function (grunt) { } }, - // Renames files for browser caching purposes - filerev: { - dist: { - src: [ - '<%= yeoman.dist %>/scripts/{,*/}*.js', - '<%= yeoman.dist %>/styles/*.css', - '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', - '<%= yeoman.dist %>/styles/fonts/*' - ] - } - }, - // Reads HTML for usemin blocks to enable smart builds that automatically // concat, minify and revision files. Creates configurations in memory so // additional tasks can operate on them @@ -235,7 +234,7 @@ module.exports = function (grunt) { html: ['<%= yeoman.dist %>/{,*/}*.html'], css: ['<%= yeoman.dist %>/styles/*.css'], options: { - assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images'] + assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/assets'] } }, @@ -243,24 +242,35 @@ module.exports = function (grunt) { // By default, your `index.html`'s will take care of // minification. These next options are pre-configured if you do not wish // to use the Usemin blocks. - // cssmin: { - // dist: { - // files: { - // '<%= yeoman.dist %>/styles/main.css': [ - // '.tmp/styles/{,*/}*.css' - // ] - // } - // } - // }, - // uglify: { - // dist: { - // files: { - // '<%= yeoman.dist %>/scripts/scripts.js': [ - // '<%= yeoman.dist %>/scripts/scripts.js' - // ] - // } - // } - // }, + cssmin: { + dist: { + files: { + '<%= yeoman.dist %>/styles/main.css': [ + '.tmp/styles/{,*/}*.css' + ] + } + } + }, + + uglify: { + options: { + mangle: { + screw_ie8: true + }, + preserveComments: 'some', + compress: { + screw_ie8: true, + sequences: true, + dead_code: true, + conditionals: true, + booleans: true, + unused: true, + if_return: true, + join_vars: true, + drop_console: true + } + } + }, // concat: { // dist: {} // }, @@ -269,9 +279,9 @@ module.exports = function (grunt) { dist: { files: [{ expand: true, - cwd: '<%= yeoman.app %>/images', + cwd: '<%= yeoman.app %>/assets/images', src: '{,*/}*.svg', - dest: '<%= yeoman.dist %>/images' + dest: '<%= yeoman.dist %>/assets/images' }] } }, @@ -288,7 +298,11 @@ module.exports = function (grunt) { files: [{ expand: true, cwd: '<%= yeoman.dist %>', - src: ['*.html', 'views/{,*/}*.html'], + src: [ + '*.html', + 'app/**/*.html', + 'components/**/*.html' + ], dest: '<%= yeoman.dist %>' }] } @@ -306,18 +320,21 @@ module.exports = function (grunt) { '*.{ico,png,txt}', '.htaccess', '*.html', - 'views/{,*/}*.html', - 'images/*', - 'fonts/*', - 'WEB-INF/*', - 'scripts/ace/{,*/}/{,*/}/*' + 'assets/styles/**/*', + 'assets/images/**/*', + 'WEB-INF/*' ] + }, { + // copy fonts + expand : true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist %>', + src: ['fonts/**/*.{eot,svg,ttf,woff}'] }, { expand : true, - dot : true, cwd: '<%= yeoman.app %>', dest: '<%= yeoman.dist %>', - src: ['styles/looknfeel/*'] + src: ['app/**/*.html', 'components/**/*.html'] }, { expand: true, cwd: '.tmp/images', @@ -337,9 +354,10 @@ module.exports = function (grunt) { }, styles: { expand: true, - cwd: '<%= yeoman.app %>/styles', + flatten: true, + cwd: '<%= yeoman.app %>', dest: '.tmp/styles/', - src: '{,*/}*.css' + src: '{fonts,components,app}/**/*.css' } }, @@ -378,7 +396,6 @@ module.exports = function (grunt) { 'concurrent:server', 'autoprefixer', 'connect:livereload', - /*'newer:jshint'*/ 'watch' ]); }); @@ -407,7 +424,6 @@ module.exports = function (grunt) { 'copy:dist', 'cssmin', 'uglify', - /*'filerev',*/ 'usemin', 'htmlmin' ]); diff --git a/zeppelin-web/README.md b/zeppelin-web/README.md index 4df6e4c7ccb..cbd7d73b2d3 100644 --- a/zeppelin-web/README.md +++ b/zeppelin-web/README.md @@ -1,12 +1,34 @@ # Zeppelin Web Application -This is a Zeppelin web frontend project. +This is Zeppelin's frontend project. ## Compile Zeppelin web -If you want to compile the WebApplication, you will have to simply run `mvn package`. + +### New environment + +If you want to compile the WebApplication only, you will have to simply run `mvn package` in this folder. + This will Download all the dependencies including node js and npm (you will find the binaries in the folder `zeppelin-web/node`). -We also provide some **helper script** for bower and grunt (you dont need to install them). +We are supposed to provide some **helper script** for __bower__ and __grunt__, but they are currently outdated, so you might want install them on your machine and use them instead. + +### Configured environment + +Here are the basic commands to compile the WebApplication with a configured environment (Installed grunt, bower, npm) + +**Build the application for production** + +`./grunt build` + +**Run the application in dev mode** + +``./grunt serve`` + +This will launch a Zeppelin WebApplication on port **9000** and update on code changes. +(You will need to have Zeppelin running on the side) + + +#### Troubleshooting In case of the error `ECMDERR Failed to execute "git ls-remote --tags --heads git://xxxxx", exit code of #128` @@ -24,31 +46,4 @@ Try to add to the `.bowerrc` file the following content: and retry to build again. ## Contribute on Zeppelin Web -If you wish to help us to contribute on Zeppelin Web, you will need to install some deps. -Here this is a good start to understand how zeppelin web is architectured. -http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/ - -### Run the application in dev mode -``./grunt serve`` - -### Build the application -`./grunt build` - -### Add composents to Zeppelin Webapp - * New controller : `yo angular:controller ` - * New directive : `yo angular:directive ` - * New service : `yo angular:service ` - - ### Add plugin - - `./bower install -save` - update the file index.html with the new bower_components - - ex: `./bower install angular-nvd3` - ``` - - ```` - - - - +If you wish to help us and contribute to Zeppelin WebApplication, please look at [Zeppelin WebApplication's contribution guideline](CONTRIBUTING.md). diff --git a/zeppelin-web/app/scripts/app.js b/zeppelin-web/app/scripts/app.js deleted file mode 100644 index b311b7c2307..00000000000 --- a/zeppelin-web/app/scripts/app.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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. - */ -'use strict'; - -/** Get the current port of the websocket - * - * In the case of running the zeppelin-server normally, - * the body of this function is just filler. It will be dynamically - * overridden with the AppScriptServlet from zeppelin-site.xml config value - * when the client requests the script. - * - * If the config value is not defined, it defaults to the HTTP port + 1 - * - * At the moment, the key delimiter denoting the end of this function - * during the replacement is the '}' character. - * - * !!! - * Avoid using '}' inside the function body or you will fail running - * in server mode. - * !!! - * - * In the case of running "grunt serve", this function will appear - * as is. - */ -function getPort() { - var port = Number(location.port); - if (location.protocol !== 'https:' && !!port) - port = 80; - else if (location.protocol === 'https:' && !!port) - port = 443; - else if (port === 3333 || port === 9000) - port = 8080; - - return port+1; -} - -function getWebsocketProtocol() { - return location.protocol === 'https:' ? 'wss' : 'ws'; -} - -function getRestApiBase() { - var port = Number(location.port); - if (!!port) { - port = 80; - if (location.protocol === 'https:') { - port = 443; - } - } - - if (port === 3333 || port === 9000) { - port = 8080; - } - return location.protocol + "//" + location.hostname + ":" + port + skipTrailingSlash(location.pathname) + "/api"; -} - -function skipTrailingSlash(path) { - return path.replace(/\/$/, ""); -} - -/** - * @ngdoc overview - * @name zeppelinWebApp - * @description - * # zeppelinWebApp - * - * Main module of the application. - * - * @author anthonycorbacho - */ -angular - .module('zeppelinWebApp', [ - 'ngAnimate', - 'ngCookies', - 'ngRoute', - 'ngSanitize', - 'angular-websocket', - 'ui.ace', - 'ui.bootstrap', - 'ui.sortable', - 'ngTouch', - 'ngDragDrop', - 'monospaced.elastic', - 'puElasticInput', - 'xeditable' - ]) - .filter('breakFilter', function () { - return function (text) { - if (!!text) return text.replace(/\n/g, '
'); - }; - }) - .config(function ($routeProvider, WebSocketProvider) { - WebSocketProvider - .prefix('') - .uri(getWebsocketProtocol() + '://' + location.hostname + ':' + getPort()); - - $routeProvider - .when('/', { - templateUrl: 'views/main.html' - }) - .when('/notebook/:noteId', { - templateUrl: 'views/notebooks.html', - controller: 'NotebookCtrl' - }) - .when('/notebook/:noteId/paragraph/:paragraphId?', { - templateUrl: 'views/notebooks.html', - controller: 'NotebookCtrl' - }) - .when('/interpreter', { - templateUrl: 'views/interpreter.html', - controller: 'InterpreterCtrl' - }) - .otherwise({ - redirectTo: '/' - }); - }); diff --git a/zeppelin-web/app/scripts/controllers/interpreter.js b/zeppelin-web/app/scripts/controllers/interpreter.js deleted file mode 100644 index 0da1baaf061..00000000000 --- a/zeppelin-web/app/scripts/controllers/interpreter.js +++ /dev/null @@ -1,313 +0,0 @@ -/* global confirm:false, alert:false */ -/* jshint loopfunc: true */ -/* - * 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. - */ -'use strict'; - -/** - * @ngdoc function - * @name zeppelinWebApp.controller:InterpreterCtrl - * @description - * # InterpreterCtrl - * Controller of interpreter, manage the note (update) - */ -angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope, $route, $routeParams, $location, $rootScope, $http) { - - var remoteSettingToLocalSetting = function(settingId, setting) { - var property = {}; - for (var key in setting.properties) { - property[key] = { - value : setting.properties[key] - }; - } - return { - id : settingId, - name : setting.name, - group : setting.group, - option : angular.copy(setting.option), - properties : property, - interpreters : setting.interpreterGroup - }; - }; - - var getInterpreterSettings = function() { - $http.get(getRestApiBase()+'/interpreter/setting'). - success(function(data, status, headers, config) { - var interpreterSettings = []; - //console.log("getInterpreterSettings=%o", data); - - for (var settingId in data.body) { - var setting = data.body[settingId]; - interpreterSettings.push(remoteSettingToLocalSetting(setting.id, setting)); - } - $scope.interpreterSettings = interpreterSettings; - }). - error(function(data, status, headers, config) { - console.log('Error %o %o', status, data.message); - }); - }; - - var getAvailableInterpreters = function() { - $http.get(getRestApiBase()+'/interpreter'). - success(function(data, status, headers, config) { - var groupedInfo = {}; - var info; - for (var k in data.body) { - info = data.body[k]; - if (!groupedInfo[info.group]) { - groupedInfo[info.group] = []; - } - groupedInfo[info.group].push({ - name : info.name, - className : info.className, - properties : info.properties - }); - } - - $scope.availableInterpreters = groupedInfo; - //console.log("getAvailableInterpreters=%o", data); - }). - error(function(data, status, headers, config) { - console.log('Error %o %o', status, data.message); - }); - }; - - $scope.copyOriginInterpreterSettingProperties = function(settingId) { - $scope.interpreterSettingProperties = {}; - for (var i=0; i < $scope.interpreterSettings.length; i++) { - var setting = $scope.interpreterSettings[i]; - if(setting.id === settingId) { - angular.copy(setting.properties, $scope.interpreterSettingProperties); - angular.copy(setting.option, $scope.interpreterSettingOption); - break; - } - } - console.log('%o, %o', $scope.interpreterSettings[i], $scope.interpreterSettingProperties); - }; - - $scope.updateInterpreterSetting = function(settingId) { - var result = confirm('Do you want to update this interpreter and restart with new settings?'); - if (!result) { - return; - } - - $scope.addNewInterpreterProperty(settingId); - - var request = { - option : { - remote : true - }, - properties : {}, - }; - - for (var i=0; i < $scope.interpreterSettings.length; i++) { - var setting = $scope.interpreterSettings[i]; - if(setting.id === settingId) { - request.option = angular.copy(setting.option); - for (var p in setting.properties) { - request.properties[p] = setting.properties[p].value; - } - break; - } - } - - $http.put(getRestApiBase()+'/interpreter/setting/'+settingId, request). - success(function(data, status, headers, config) { - for (var i=0; i < $scope.interpreterSettings.length; i++) { - var setting = $scope.interpreterSettings[i]; - if (setting.id === settingId) { - $scope.interpreterSettings.splice(i, 1); - $scope.interpreterSettings.splice(i, 0, remoteSettingToLocalSetting(settingId, data.body)); - break; - } - } - }). - error(function(data, status, headers, config) { - console.log('Error %o %o', status, data.message); - }); - }; - - $scope.resetInterpreterSetting = function(settingId){ - for (var i=0; i<$scope.interpreterSettings.length; i++) { - var setting = $scope.interpreterSettings[i]; - if (setting.id === settingId) { - angular.copy($scope.interpreterSettingProperties, setting.properties); - angular.copy($scope.interpreterSettingOption, setting.option); - break; - } - } - }; - - $scope.removeInterpreterSetting = function(settingId) { - var result = confirm('Do you want to delete this interpreter setting?'); - if (!result) { - return; - } - - console.log('Delete setting %o', settingId); - $http.delete(getRestApiBase()+'/interpreter/setting/'+settingId). - success(function(data, status, headers, config) { - for (var i=0; i < $scope.interpreterSettings.length; i++) { - var setting = $scope.interpreterSettings[i]; - if (setting.id === settingId) { - $scope.interpreterSettings.splice(i, 1); - break; - } - } - }). - error(function(data, status, headers, config) { - console.log('Error %o %o', status, data.message); - }); - }; - - $scope.newInterpreterGroupChange = function() { - var property = {}; - var intpGroupInfo = $scope.availableInterpreters[$scope.newInterpreterSetting.group]; - for (var i=0; i -1) ? true : false); - }; - init(); - - /** - * Web socket - */ - WebSocket.onopen(function() { - console.log('Websocket created'); - $scope.connected = true; - if ($scope.WebSocketWaitingList.length > 0) { - for (var o in $scope.WebSocketWaitingList) { - WebSocket.send(JSON.stringify($scope.WebSocketWaitingList[o])); - } - } - setInterval(function(){ - $rootScope.$emit('sendNewEvent', {op: 'PING'}) - } - ,60000); - }); - - WebSocket.onmessage(function(event) { - var payload; - if (event.data) { - payload = angular.fromJson(event.data); - } - console.log('Receive << %o, %o, %o', payload.op, payload, $scope); - var op = payload.op; - var data = payload.data; - if (op === 'NOTE') { - $scope.$broadcast('setNoteContent', data.note); - } else if (op === 'NOTES_INFO') { - $scope.$broadcast('setNoteMenu', data.notes); - } else if (op === 'PARAGRAPH') { - $scope.$broadcast('updateParagraph', data); - } else if (op === 'PROGRESS') { - $scope.$broadcast('updateProgress', data); - } else if (op === 'COMPLETION_LIST') { - $scope.$broadcast('completionList', data); - } else if (op === 'ANGULAR_OBJECT_UPDATE') { - $scope.$broadcast('angularObjectUpdate', data); - } - }); - - WebSocket.onerror(function(event) { - console.log('error message: ', event); - $scope.connected = false; - }); - - WebSocket.onclose(function(event) { - console.log('close message: ', event); - $scope.connected = false; - }); - - /** Send info to the websocket server */ - var send = function(data) { - if (WebSocket.currentState() !== 'OPEN') { - $scope.WebSocketWaitingList.push(data); - } else { - console.log('Send >> %o, %o', data.op, data); - WebSocket.send(JSON.stringify(data)); - } - }; - - - /** get the childs event and sebd to the websocket server */ - $rootScope.$on('sendNewEvent', function(event, data) { - if (!event.defaultPrevented) { - send(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 !== '') { - $scope.looknfeel = data; - event.preventDefault(); - } - }); - -}); diff --git a/zeppelin-web/app/styles/typography.css b/zeppelin-web/app/styles/typography.css deleted file mode 100644 index 5050f193154..00000000000 --- a/zeppelin-web/app/styles/typography.css +++ /dev/null @@ -1,46 +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. - */ - -/** concept from http://www.google.com/design/spec/style/typography.html#typography-standard-styles */ - - -h1, h2, h3, h4, h5, h6 { - font-family: 'RobotoDraft', sans-serif; - color: black; - text-rendering: optimizeLegibility; -} -h1 { - font-size: 2.25em; -} -h2 { - font-size: 2em; -} -h3 { - font-size: 1.75em; -} -h4 { - font-size: 1.5em; -} -h5 { - font-size: 1.25em; -} -h6 { - font-size: 1em; -} - -.btnText { - text-transform: uppercase; - font-size: 12px; - text-decoration: none!important; -} \ No newline at end of file diff --git a/zeppelin-web/bower.json b/zeppelin-web/bower.json index 3945983e630..57ea00d1118 100644 --- a/zeppelin-web/bower.json +++ b/zeppelin-web/bower.json @@ -12,7 +12,7 @@ "angular-touch": "1.3.8", "angular-route": "1.3.8", "angular-bootstrap": "~0.11.0", - "angular-websocket": "~0.0.5", + "angular-websocket": "~1.0.13", "ace-builds": "1.1.8", "angular-ui-ace": "0.1.1", "jquery.scrollTo": "~1.4.13", @@ -22,29 +22,37 @@ "ng-sortable": "~1.1.9", "angular-elastic": "~2.4.2", "angular-elastic-input": "~2.0.1", - "angular-xeditable" : "0.1.8", - "highlightjs": "~8.4.0" + "angular-xeditable": "0.1.8", + "highlightjs": "~8.4.0", + "lodash": "~3.9.3" }, "devDependencies": { "angular-mocks": "1.3.8", "angular-scenario": "1.3.8" }, - "appPath": "app", + "appPath": "src", + "resolutions": { + "perfect-scrollbar": "~0.5.4" + }, "overrides": { "ace-builds": { - "main": ["src-noconflict/ace.js", - "src-noconflict/mode-scala.js", - "src-noconflict/mode-sql.js", - "src-noconflict/mode-markdown.js", - "src-noconflict/keybinding-emacs.js", - "src-noconflict/ext-language_tools.js", - "src-noconflict/theme-github.js"], + "main": [ + "src-noconflict/ace.js", + "src-noconflict/mode-scala.js", + "src-noconflict/mode-sql.js", + "src-noconflict/mode-markdown.js", + "src-noconflict/keybinding-emacs.js", + "src-noconflict/ext-language_tools.js", + "src-noconflict/theme-github.js" + ], "version": "1.1.8", "name": "ace-builds" }, "highlightjs": { - "main": ["highlight.pack.js", - "styles/github.css"], + "main": [ + "highlight.pack.js", + "styles/github.css" + ], "version": "8.4.0", "name": "highlightjs" } diff --git a/zeppelin-web/package.json b/zeppelin-web/package.json index 670ab7f7739..e984e889ecc 100644 --- a/zeppelin-web/package.json +++ b/zeppelin-web/package.json @@ -1,7 +1,10 @@ { "name": "zeppelin-web", "version": "0.0.0", - "dependencies": {}, + "dependencies": { + "grunt-angular-templates": "^0.5.7", + "grunt-dom-munger": "^3.4.0" + }, "devDependencies": { "bower": "", "grunt": "^0.4.1", diff --git a/zeppelin-web/pom.xml b/zeppelin-web/pom.xml index f4549ad1674..316fae738b2 100644 --- a/zeppelin-web/pom.xml +++ b/zeppelin-web/pom.xml @@ -33,6 +33,14 @@ + + org.apache.maven.plugins + maven-war-plugin + + dist + dist\WEB-INF\web.xml + + org.apache.rat apache-rat-plugin @@ -50,22 +58,21 @@ **/.settings/* **/.classpath **/.project - **/target/** + **/target/** node/** node_modules/** bower_components/** test/** - src/main/webapp/** - app/.buildignore - app/fonts/fontawesome* - app/fonts/font-awesome* - app/styles/font-awesome* - app/fonts/Simple-Line* - app/fonts/simple-line* - app/styles/simple-line* + dist/** + src/.buildignore + src/fonts/fontawesome* + src/fonts/font-awesome* + src/styles/font-awesome* + src/fonts/Simple-Line* + src/fonts/simple-line* bower.json package.json - README.md + *.md @@ -93,7 +100,7 @@ npm - + bower install diff --git a/zeppelin-web/app/.buildignore b/zeppelin-web/src/.buildignore similarity index 100% rename from zeppelin-web/app/.buildignore rename to zeppelin-web/src/.buildignore diff --git a/zeppelin-web/app/404.html b/zeppelin-web/src/404.html similarity index 100% rename from zeppelin-web/app/404.html rename to zeppelin-web/src/404.html diff --git a/zeppelin-web/app/WEB-INF/web.xml b/zeppelin-web/src/WEB-INF/web.xml similarity index 100% rename from zeppelin-web/app/WEB-INF/web.xml rename to zeppelin-web/src/WEB-INF/web.xml diff --git a/zeppelin-web/src/app/app.controller.js b/zeppelin-web/src/app/app.controller.js new file mode 100644 index 00000000000..f2bf8ab0cfc --- /dev/null +++ b/zeppelin-web/src/app/app.controller.js @@ -0,0 +1,45 @@ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp').controller('MainCtrl', function($scope, $rootScope, $window) { + $rootScope.compiledScope = $scope.$new(true, $rootScope); + $scope.looknfeel = 'default'; + + var init = function() { + $scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true : false); + }; + + init(); + + $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(); + } + }); + + // Set The lookAndFeel to default on every page + $rootScope.$on('$routeChangeStart', function(event, next, current) { + $rootScope.$broadcast('setLookAndFeel', 'default'); + }); + +}); diff --git a/zeppelin-web/src/app/app.js b/zeppelin-web/src/app/app.js new file mode 100644 index 00000000000..0d163d9f44f --- /dev/null +++ b/zeppelin-web/src/app/app.js @@ -0,0 +1,62 @@ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp', [ + 'ngAnimate', + 'ngCookies', + 'ngRoute', + 'ngSanitize', + 'angular-websocket', + 'ui.ace', + 'ui.bootstrap', + 'ui.sortable', + 'ngTouch', + 'ngDragDrop', + 'monospaced.elastic', + 'puElasticInput', + 'xeditable' + ]) + .filter('breakFilter', function() { + return function (text) { + if (!!text) { + return text.replace(/\n/g, '
'); + } + }; + }) + .config(function ($routeProvider) { + $routeProvider + .when('/', { + templateUrl: 'app/home/home.html', + controller: 'HomeCtrl' + }) + .when('/notebook/:noteId', { + templateUrl: 'app/notebook/notebook.html', + controller: 'NotebookCtrl' + }) + .when('/notebook/:noteId/paragraph/:paragraphId?', { + templateUrl: 'app/notebook/notebook.html', + controller: 'NotebookCtrl' + }) + .when('/interpreter', { + templateUrl: 'app/interpreter/interpreter.html', + controller: 'InterpreterCtrl' + }) + .otherwise({ + redirectTo: '/' + }); + }); diff --git a/zeppelin-web/app/scripts/ace/textarea/src/ace-bookmarklet.js b/zeppelin-web/src/app/home/home.controller.js similarity index 70% rename from zeppelin-web/app/scripts/ace/textarea/src/ace-bookmarklet.js rename to zeppelin-web/src/app/home/home.controller.js index f723f43b4b4..e66201c3f49 100644 --- a/zeppelin-web/app/scripts/ace/textarea/src/ace-bookmarklet.js +++ b/zeppelin-web/src/app/home/home.controller.js @@ -11,4 +11,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -alert("moved to https://ajaxorg.github.io/ace-builds/demo/bookmarklet/index.html. Please update your bookmark") +'use strict'; + +angular.module('zeppelinWebApp').controller('HomeCtrl', function($scope, notebookListDataFactory, websocketMsgSrv) { + + var vm = this; + vm.notes = notebookListDataFactory; + vm.websocketMsgSrv = websocketMsgSrv; + +}); diff --git a/zeppelin-web/app/styles/main.css b/zeppelin-web/src/app/home/home.css similarity index 97% rename from zeppelin-web/app/styles/main.css rename to zeppelin-web/src/app/home/home.css index f9cbed825f3..5058cb8832a 100644 --- a/zeppelin-web/app/styles/main.css +++ b/zeppelin-web/src/app/home/home.css @@ -184,7 +184,7 @@ a.navbar-brand:hover { margin-bottom: 20px; } -.box, +.box, .well { background-color: #ffffff; border-color: #e5e5e5; @@ -228,7 +228,7 @@ h6.box-heading{ .zeppelin { - background-image: url('../images/zepLogo.png'); + background-image: url('/assets/images/zepLogo.png'); background-repeat: no-repeat; background-position: right; height: 380px; @@ -236,7 +236,7 @@ h6.box-heading{ } .zeppelin2 { - background-image: url('../images/zepLogo.png'); + background-image: url('/assets/images/zepLogo.png'); background-repeat: no-repeat; background-position: right; background-position-y: 12px; @@ -277,9 +277,9 @@ kbd { } -/* -temporary fix for bootstrap issue (https://github.com/twbs/bootstrap/issues/5865) -This part should be removed when new version of bootstrap handles this issue. +/* +temporary fix for bootstrap issue (https://github.com/twbs/bootstrap/issues/5865) +This part should be removed when new version of bootstrap handles this issue. */ .btn-group > .tooltip + .btn, .btn-group > .popover + .btn { diff --git a/zeppelin-web/app/views/main.html b/zeppelin-web/src/app/home/home.html similarity index 82% rename from zeppelin-web/app/views/main.html rename to zeppelin-web/src/app/home/home.html index c6e875503f6..9e7963c7dbd 100644 --- a/zeppelin-web/app/views/main.html +++ b/zeppelin-web/src/app/home/home.html @@ -3,7 +3,7 @@ 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 +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, @@ -11,7 +11,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -
+ +
@@ -25,10 +26,11 @@

Notebook

-
-
Create new note
+
+
+ Create new note
diff --git a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html new file mode 100644 index 00000000000..e7096f64e0f --- /dev/null +++ b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html @@ -0,0 +1,77 @@ + +
+
+
+
+
+

Create new interpreter

+ +
+ Name + +
+ + Interpreter +
+ +
+ + Properties + + + + + + + + + + + + + + + + + + + + +
namevaluedescriptionaction
{{key}}{{value.description}} +
+
+
+ + +
+
+
+ + + Save + + + Cancel + +
+
+
+
\ No newline at end of file diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js b/zeppelin-web/src/app/interpreter/interpreter.controller.js new file mode 100644 index 00000000000..499c270cf8a --- /dev/null +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js @@ -0,0 +1,202 @@ +/* global confirm:false, alert:false, _:false */ +/* jshint loopfunc: true */ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope, $route, $routeParams, $location, $rootScope, + $http, baseUrlSrv) { + var interpreterSettingsTmp = []; + $scope.interpreterSettings = []; + $scope.availableInterpreters = {}; + $scope.showAddNewSetting = false; + + var getInterpreterSettings = function() { + $http.get(baseUrlSrv.getRestApiBase()+'/interpreter/setting'). + success(function(data, status, headers, config) { + $scope.interpreterSettings = data.body; + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + var getAvailableInterpreters = function() { + $http.get(baseUrlSrv.getRestApiBase()+'/interpreter'). + success(function(data, status, headers, config) { + $scope.availableInterpreters = data.body; + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + var emptyNewProperty = function(object) { + angular.extend(object, {propertyValue: '', propertyKey: ''}); + }; + + var removeTMPSettings = function(index) { + interpreterSettingsTmp.splice(index, 1); + }; + + $scope.copyOriginInterpreterSettingProperties = function(settingId) { + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + interpreterSettingsTmp[index] = angular.copy($scope.interpreterSettings[index]); + }; + + $scope.updateInterpreterSetting = function(settingId) { + var result = confirm('Do you want to update this interpreter and restart with new settings?'); + if (!result) { + return; + } + + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + + var request = { + option : angular.copy($scope.interpreterSettings[index].option), + properties : angular.copy($scope.interpreterSettings[index].properties), + }; + + + $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/' + settingId, request). + success(function(data, status, headers, config) { + $scope.interpreterSettings[index] = data.body; + removeTMPSettings(index); + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + $scope.resetInterpreterSetting = function(settingId){ + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + + // Set the old settings back + $scope.interpreterSettings[index] = angular.copy(interpreterSettingsTmp[index]); + removeTMPSettings(index); + }; + + $scope.removeInterpreterSetting = function(settingId) { + var result = confirm('Do you want to delete this interpreter setting?'); + if (!result) { + return; + } + + $http.delete(baseUrlSrv.getRestApiBase() + '/interpreter/setting/' + settingId). + success(function(data, status, headers, config) { + + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + $scope.interpreterSettings.splice(index, 1); + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + $scope.newInterpreterGroupChange = function() { + $scope.newInterpreterSetting.properties = $scope.availableInterpreters[$scope.newInterpreterSetting.group].properties; + }; + + $scope.restartInterpreterSetting = function(settingId) { + var result = confirm('Do you want to restart this interpreter?'); + if (!result) { + return; + } + + $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/restart/' + settingId). + success(function(data, status, headers, config) { + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + $scope.interpreterSettings[index] = data.body; + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + $scope.addNewInterpreterSetting = function() { + if (!$scope.newInterpreterSetting.name || !$scope.newInterpreterSetting.group) { + alert('Please determine name and interpreter'); + return; + } + + if (_.findIndex($scope.interpreterSettings, { 'name': $scope.newInterpreterSetting.name }) >= 0) { + alert('Name ' + $scope.newInterpreterSetting.name + ' already exists'); + return; + } + + var newSetting = angular.copy($scope.newInterpreterSetting); + + for (var p in $scope.newInterpreterSetting.properties) { + newSetting.properties[p] = $scope.newInterpreterSetting.properties[p].value; + } + + $http.post(baseUrlSrv.getRestApiBase()+'/interpreter/setting', newSetting). + success(function(data, status, headers, config) { + $scope.resetNewInterpreterSetting(); + getInterpreterSettings(); + $scope.showAddNewSetting = false; + }). + error(function(data, status, headers, config) { + console.log('Error %o %o', status, data.message); + }); + }; + + + $scope.resetNewInterpreterSetting = function() { + $scope.newInterpreterSetting = { + name : undefined, + group : undefined, + option : { remote : true }, + properties : {} + }; + emptyNewProperty($scope.newInterpreterSetting); + }; + + $scope.removeInterpreterProperty = function(key, settingId) { + if (settingId === undefined) { + delete $scope.newInterpreterSetting.properties[key]; + } + else { + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + delete $scope.interpreterSettings[index].properties[key]; + } + }; + + $scope.addNewInterpreterProperty = function(settingId) { + if(settingId === undefined) { + // Add new property from create form + if (!$scope.newInterpreterSetting.propertyKey || $scope.newInterpreterSetting.propertyKey === '') { + return; + } + $scope.newInterpreterSetting.properties[$scope.newInterpreterSetting.propertyKey] = $scope.newInterpreterSetting.propertyValue; + emptyNewProperty($scope.newInterpreterSetting); + } + else { + // Add new property from create form + var index = _.findIndex($scope.interpreterSettings, { 'id': settingId }); + var setting = $scope.interpreterSettings[index]; + + setting.properties[setting.propertyKey] = setting.propertyValue; + emptyNewProperty(setting); + } + }; + + var init = function() { + $scope.resetNewInterpreterSetting(); + getInterpreterSettings(); + getAvailableInterpreters(); + }; + + init(); +}); diff --git a/zeppelin-web/app/styles/interpreter.css b/zeppelin-web/src/app/interpreter/interpreter.css similarity index 100% rename from zeppelin-web/app/styles/interpreter.css rename to zeppelin-web/src/app/interpreter/interpreter.css diff --git a/zeppelin-web/app/views/interpreter.html b/zeppelin-web/src/app/interpreter/interpreter.html similarity index 59% rename from zeppelin-web/app/views/interpreter.html rename to zeppelin-web/src/app/interpreter/interpreter.html index 2bd3fb3b4a9..69b47661153 100644 --- a/zeppelin-web/app/views/interpreter.html +++ b/zeppelin-web/src/app/interpreter/interpreter.html @@ -31,83 +31,7 @@

-
-
-
-
-
-

Create new interpreter

- -
- Name - - -
- - Interpreter -
- -
- - Properties - - - - - - - - - - - - - - - - - - - - -
namevaluedescriptionaction
{{key}}{{value.description}} -
-
-
- - - -
-
-
- - - Save - - - Cancel - -
-
-
-
+

Create new interpreter

{{setting.name}} - , %{{interpreter.name}} @@ -151,8 +75,8 @@

{{setting.name}} {{key}} - - {{value.value | breakFilter}} + + {{value | breakFilter}} diff --git a/zeppelin-web/app/scripts/controllers/notebook.js b/zeppelin-web/src/app/notebook/notebook.controller.js similarity index 89% rename from zeppelin-web/app/scripts/controllers/notebook.js rename to zeppelin-web/src/app/notebook/notebook.controller.js index 9a9fcd7ce99..0d01c370ab3 100644 --- a/zeppelin-web/app/scripts/controllers/notebook.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -15,15 +15,7 @@ */ 'use strict'; -/** - * @ngdoc function - * @name zeppelinWebApp.controller:NotebookCtrl - * @description - * # NotebookCtrl - * Controller of notes, manage the note (update) - * - */ -angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $route, $routeParams, $location, $rootScope, $http) { +angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $route, $routeParams, $location, $rootScope, $http, websocketMsgSrv, baseUrlSrv) { $scope.note = null; $scope.showEditor = false; $scope.editorToggled = false; @@ -61,7 +53,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro /** Init the new controller */ var initNotebook = function() { - $rootScope.$emit('sendNewEvent', {op: 'GET_NOTE', data: {id: $routeParams.noteId}}); + websocketMsgSrv.getNotebook($routeParams.noteId); }; initNotebook(); @@ -71,7 +63,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro $scope.removeNote = function(noteId) { var result = confirm('Do you want to delete this notebook?'); if (result) { - $rootScope.$emit('sendNewEvent', {op: 'DEL_NOTE', data: {id: noteId}}); + websocketMsgSrv.deleteNotebook(noteId); $location.path('/#'); } }; @@ -145,14 +137,14 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro if(config) { $scope.note.config = config; } - $rootScope.$emit('sendNewEvent', {op: 'NOTE_UPDATE', data: {id: $scope.note.id, name: $scope.note.name, config : $scope.note.config}}); + websocketMsgSrv.updateNotebook($scope.note.id, $scope.note.name, $scope.note.config); }; /** Update the note name */ $scope.sendNewName = function() { $scope.showEditor = false; if ($scope.note.name) { - $rootScope.$emit('sendNewEvent', {op: 'NOTE_UPDATE', data: {id: $scope.note.id, name: $scope.note.name, config : $scope.note.config}}); + websocketMsgSrv.updateNotebook($scope.note.id, $scope.note.name, $scope.note.config); } }; @@ -162,7 +154,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro $scope.asIframe = $routeParams.asIframe; if ($scope.paragraphUrl) { note = cleanParagraphExcept($scope.paragraphUrl, note); - $rootScope.$emit('setIframe', $scope.asIframe); + $rootScope.$broadcast('setIframe', $scope.asIframe); } if ($scope.note === null) { @@ -182,13 +174,9 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro } else { $scope.viewOnly = $scope.note.config.looknfeel === 'report' ? true : false; } - $rootScope.$emit('setLookAndFeel', $scope.note.config.looknfeel); + $rootScope.$broadcast('setLookAndFeel', $scope.note.config.looknfeel); }; - - - - var cleanParagraphExcept = function(paragraphId, note) { var noteCopy = {}; noteCopy.id = note.id; @@ -222,7 +210,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) { return; } - $rootScope.$emit('sendNewEvent', { op: 'MOVE_PARAGRAPH', data : {id: paragraphId, index: newIndex}}); + websocketMsgSrv.moveParagraph(paragraphId, newIndex); }); // create new paragraph on current position @@ -242,7 +230,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro if (newIndex < 0 || newIndex > $scope.note.paragraphs.length) { return; } - $rootScope.$emit('sendNewEvent', { op: 'INSERT_PARAGRAPH', data : {index: newIndex}}); + websocketMsgSrv.insertParagraph(newIndex); }); $scope.$on('moveParagraphDown', function(event, paragraphId) { @@ -257,7 +245,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) { return; } - $rootScope.$emit('sendNewEvent', { op: 'MOVE_PARAGRAPH', data : {id: paragraphId, index: newIndex}}); + websocketMsgSrv.moveParagraph(paragraphId, newIndex); }); $scope.$on('moveFocusToPreviousParagraph', function(event, currentParagraphId){ @@ -351,7 +339,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro }; var getInterpreterBindings = function(callback) { - $http.get(getRestApiBase()+ '/notebook/interpreter/bind/' +$scope.note.id). + $http.get(baseUrlSrv.getRestApiBase()+ '/notebook/interpreter/bind/' +$scope.note.id). success(function(data, status, headers, config) { $scope.interpreterBindings = data.body; $scope.interpreterBindingsOrig = jQuery.extend(true, [], $scope.interpreterBindings); // to check dirty @@ -418,7 +406,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro } } - $http.put(getRestApiBase() + '/notebook/interpreter/bind/' + $scope.note.id, + $http.put(baseUrlSrv.getRestApiBase() + '/notebook/interpreter/bind/' + $scope.note.id, selectedSettingIds). success(function(data, status, headers, config) { console.log('Interpreter binding %o saved', selectedSettingIds); @@ -458,7 +446,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro if (!angularObjectRegistry[varName]) { angularObjectRegistry[varName] = { interpreterGroupId : data.interpreterGroupId, - } + }; } angularObjectRegistry[varName].skipEmit = true; @@ -469,16 +457,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro angularObjectRegistry[varName].skipEmit = false; return; } - - $rootScope.$emit('sendNewEvent', { - op: 'ANGULAR_OBJECT_UPDATED', - data: { - noteId: $routeParams.noteId, - name:varName, - value:newValue, - interpreterGroupId:angularObjectRegistry[varName].interpreterGroupId - } - }); + websocketMsgSrv.updateAngularObject($routeParams.noteId, varName, newValue, angularObjectRegistry[varName].interpreterGroupId); }); } scope[varName] = data.angularObject.object; @@ -489,6 +468,6 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro var isFunction = function(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; - } + }; }); diff --git a/zeppelin-web/app/styles/notebook.css b/zeppelin-web/src/app/notebook/notebook.css similarity index 98% rename from zeppelin-web/app/styles/notebook.css rename to zeppelin-web/src/app/notebook/notebook.css index b5eb511a21d..477e7a1b680 100644 --- a/zeppelin-web/app/styles/notebook.css +++ b/zeppelin-web/src/app/notebook/notebook.css @@ -22,6 +22,15 @@ min-height: 32px; } +.paragraphForm.form-horizontal .form-group { + margin-right: 0px; + margin-left: 0px; +} + +.paragraphForm.form-horizontal .form-group label { + padding-left: 0; +} + .paragraph .tableDisplay .hljs { background: none; } @@ -266,7 +275,7 @@ .disable { - opacity:0.4!important; + opacity:0.6!important; pointer-events: none; } diff --git a/zeppelin-web/app/views/notebooks.html b/zeppelin-web/src/app/notebook/notebook.html similarity index 99% rename from zeppelin-web/app/views/notebooks.html rename to zeppelin-web/src/app/notebook/notebook.html index f3294a1a2d9..3a3f75174b9 100644 --- a/zeppelin-web/app/views/notebooks.html +++ b/zeppelin-web/src/app/notebook/notebook.html @@ -161,7 +161,7 @@
Interpreter binding
ng-class="columnWidthClass(currentParagraph.config.colWidth)" class="paragraph-col">
diff --git a/zeppelin-web/app/scripts/controllers/paragraph.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js similarity index 91% rename from zeppelin-web/app/scripts/controllers/paragraph.js rename to zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js index 7cf211e54ee..21e022a2278 100644 --- a/zeppelin-web/app/scripts/controllers/paragraph.js +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js @@ -15,17 +15,9 @@ */ 'use strict'; -/** - * @ngdoc function - * @name zeppelinWebApp.controller:ParagraphCtrl - * @description - * # ParagraphCtrl - * Controller of the paragraph, manage everything related to the paragraph - * - * @author anthonycorbacho - */ angular.module('zeppelinWebApp') - .controller('ParagraphCtrl', function($scope, $rootScope, $route, $window, $element, $routeParams, $location, $timeout, $compile) { + .controller('ParagraphCtrl', function($scope,$rootScope, $route, $window, $element, $routeParams, $location, + $timeout, $compile, websocketMsgSrv) { $scope.paragraph = null; $scope.editor = null; @@ -67,7 +59,7 @@ angular.module('zeppelinWebApp') try { $('#p'+$scope.paragraph.id+'_html').html($scope.paragraph.result.msg); - $('#p'+$scope.paragraph.id+'_html').find('pre code').each(function(i, e) { hljs.highlightBlock(e) }); + $('#p'+$scope.paragraph.id+'_html').find('pre code').each(function(i, e) { hljs.highlightBlock(e); }); } catch(err) { console.log('HTML rendering error %o', err); } @@ -159,17 +151,17 @@ angular.module('zeppelinWebApp') // TODO: this may have impact on performance when there are many paragraphs in a note. $scope.$on('updateParagraph', function(event, data) { if (data.paragraph.id === $scope.paragraph.id && - ( - data.paragraph.dateCreated !== $scope.paragraph.dateCreated || - data.paragraph.dateFinished !== $scope.paragraph.dateFinished || - data.paragraph.dateStarted !== $scope.paragraph.dateStarted || - data.paragraph.status !== $scope.paragraph.status || - data.paragraph.jobName !== $scope.paragraph.jobName || - data.paragraph.title !== $scope.paragraph.title || - data.paragraph.errorMessage !== $scope.paragraph.errorMessage || - !angular.equals(data.paragraph.settings, $scope.lastData.settings) || - !angular.equals(data.paragraph.config, $scope.lastData.config) - ) + ( + data.paragraph.dateCreated !== $scope.paragraph.dateCreated || + data.paragraph.dateFinished !== $scope.paragraph.dateFinished || + data.paragraph.dateStarted !== $scope.paragraph.dateStarted || + data.paragraph.status !== $scope.paragraph.status || + data.paragraph.jobName !== $scope.paragraph.jobName || + data.paragraph.title !== $scope.paragraph.title || + data.paragraph.errorMessage !== $scope.paragraph.errorMessage || + !angular.equals(data.paragraph.settings, $scope.lastData.settings) || + !angular.equals(data.paragraph.config, $scope.lastData.config) + ) ) { // store original data for comparison $scope.lastData.settings = angular.copy(data.paragraph.settings); @@ -247,22 +239,14 @@ angular.module('zeppelinWebApp') $scope.cancelParagraph = function() { console.log('Cancel %o', $scope.paragraph.id); - var data = {op: 'CANCEL_PARAGRAPH', data: {id: $scope.paragraph.id }}; - $rootScope.$emit('sendNewEvent', data); + websocketMsgSrv.cancelParagraphRun($scope.paragraph.id); }; $scope.runParagraph = function(data) { - var parapgraphData = {op: 'RUN_PARAGRAPH', - data: { - id: $scope.paragraph.id, - title: $scope.paragraph.title, - paragraph: data, - config: $scope.paragraph.config, - params: $scope.paragraph.settings.params - } - }; - $rootScope.$emit('sendNewEvent', parapgraphData); + websocketMsgSrv.runParagraph($scope.paragraph.id, $scope.paragraph.title, + data, $scope.paragraph.config, $scope.paragraph.settings.params); + $scope.dirtyText = undefined; }; $scope.moveUp = function() { @@ -281,8 +265,7 @@ angular.module('zeppelinWebApp') var result = confirm('Do you want to delete this paragraph?'); if (result) { console.log('Remove paragraph'); - var paragraphData = {op: 'PARAGRAPH_REMOVE', data: {id: $scope.paragraph.id}}; - $rootScope.$emit('sendNewEvent', paragraphData); + websocketMsgSrv.removeParagraph($scope.paragraph.id); } }; @@ -433,9 +416,9 @@ angular.module('zeppelinWebApp') } $scope.editor.setOptions({ - enableBasicAutocompletion: true, - enableSnippets: false, - enableLiveAutocompletion:false + enableBasicAutocompletion: true, + enableSnippets: false, + enableLiveAutocompletion:false }); var remoteCompleter = { getCompletions : function(editor, session, pos, prefix, callback) { @@ -537,23 +520,23 @@ angular.module('zeppelinWebApp') $scope.editor.keyBinding.onCommandKey = function(e, hashId, keyCode) { if ($scope.editor.completer && $scope.editor.completer.activated) { // if autocompleter is active } else { - var numRows; - var currentRow; - if (keyCode === 38 || (keyCode === 80 && e.ctrlKey)) { // UP - numRows = $scope.editor.getSession().getLength(); - currentRow = $scope.editor.getCursorPosition().row; - if (currentRow === 0) { - // move focus to previous paragraph - $scope.$emit('moveFocusToPreviousParagraph', $scope.paragraph.id); - } - } else if (keyCode === 40 || (keyCode === 78 && e.ctrlKey)) { // DOWN - numRows = $scope.editor.getSession().getLength(); - currentRow = $scope.editor.getCursorPosition().row; - if (currentRow === numRows-1) { - // move focus to next paragraph - $scope.$emit('moveFocusToNextParagraph', $scope.paragraph.id); - } + var numRows; + var currentRow; + if (keyCode === 38 || (keyCode === 80 && e.ctrlKey)) { // UP + numRows = $scope.editor.getSession().getLength(); + currentRow = $scope.editor.getCursorPosition().row; + if (currentRow === 0) { + // move focus to previous paragraph + $scope.$emit('moveFocusToPreviousParagraph', $scope.paragraph.id); } + } else if (keyCode === 40 || (keyCode === 78 && e.ctrlKey)) { // DOWN + numRows = $scope.editor.getSession().getLength(); + currentRow = $scope.editor.getCursorPosition().row; + if (currentRow === numRows-1) { + // move focus to next paragraph + $scope.$emit('moveFocusToNextParagraph', $scope.paragraph.id); + } + } } this.origOnCommandKey(e, hashId, keyCode); }; @@ -714,16 +697,7 @@ angular.module('zeppelinWebApp') }; var commitParagraph = function(title, text, config, params) { - var parapgraphData = { - op: 'COMMIT_PARAGRAPH', - data: { - id: $scope.paragraph.id, - title : title, - paragraph: text, - params: params, - config: config - }}; - $rootScope.$emit('sendNewEvent', parapgraphData); + websocketMsgSrv.commitParagraph($scope.paragraph.id, title, text, config, params); }; var setTable = function(type, data, refresh) { @@ -777,7 +751,7 @@ angular.module('zeppelinWebApp') var v = row[index].value; if (getTableContentFormat(v) !== 'html') { v = v.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { - return '&#'+i.charCodeAt(0)+';'; + return '&#'+i.charCodeAt(0)+';'; }); } html += ' '+formatTableContent(v)+''; @@ -846,23 +820,23 @@ angular.module('zeppelinWebApp') var tooltipContent = '

' + key + '

'; if ($scope.paragraph.config.graph.scatter.size && $scope.isValidSizeOption($scope.paragraph.config.graph.scatter, $scope.paragraph.result.rows)) { - tooltipContent += '

' + data.point.size + '

'; + tooltipContent += '

' + data.point.size + '

'; } return tooltipContent; }); $scope.chart[type].showDistX(true) - .showDistY(true) - //handle the problem of tooltip not showing when muliple points have same value. - .scatter.useVoronoi(false); + .showDistY(true) + //handle the problem of tooltip not showing when muliple points have same value. + .scatter.useVoronoi(false); } else { var p = pivot(data); if (type === 'pieChart') { var d = pivotDataToD3ChartFormat(p, true).d3g; $scope.chart[type].x(function(d) { return d.label;}) - .y(function(d) { return d.value;}); + .y(function(d) { return d.value;}); if ( d.length > 0 ) { for ( var i=0; i
-
+
-
+
- -
+ +
+ \ No newline at end of file diff --git a/zeppelin-web/app/scripts/directives/ngdelete.js b/zeppelin-web/src/components/ngdelete/ngdelete.directive.js similarity index 90% rename from zeppelin-web/app/scripts/directives/ngdelete.js rename to zeppelin-web/src/components/ngdelete/ngdelete.directive.js index 7d9181c28eb..1ddf1eb0074 100644 --- a/zeppelin-web/app/scripts/directives/ngdelete.js +++ b/zeppelin-web/src/components/ngdelete/ngdelete.directive.js @@ -14,12 +14,6 @@ 'use strict'; -/** - * @ngdoc directive - * @name zeppelinWebApp.directive:delete - * @description - * # ngDelete - */ angular.module('zeppelinWebApp').directive('ngDelete', function() { return function(scope, element, attrs) { element.bind('keydown keyup', function(event) { diff --git a/zeppelin-web/app/scripts/directives/ngenter.js b/zeppelin-web/src/components/ngenter/ngenter.directive.js similarity index 85% rename from zeppelin-web/app/scripts/directives/ngenter.js rename to zeppelin-web/src/components/ngenter/ngenter.directive.js index 6fc4b734ded..f284c6977b3 100644 --- a/zeppelin-web/app/scripts/directives/ngenter.js +++ b/zeppelin-web/src/components/ngenter/ngenter.directive.js @@ -13,15 +13,6 @@ */ 'use strict'; -/** - * @ngdoc directive - * @name zeppelinWebApp.directive:ngEnter - * @description - * # ngEnter - * Bind the event - * - * @author anthonycorbacho - */ angular.module('zeppelinWebApp').directive('ngEnter', function() { return function(scope, element, attrs) { element.bind('keydown keypress', function(event) { diff --git a/zeppelin-web/src/components/notebookListDataFactory/notebookList.datafactory.js b/zeppelin-web/src/components/notebookListDataFactory/notebookList.datafactory.js new file mode 100644 index 00000000000..ae48999b86d --- /dev/null +++ b/zeppelin-web/src/components/notebookListDataFactory/notebookList.datafactory.js @@ -0,0 +1,26 @@ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp').factory('notebookListDataFactory', function() { + var notes = {}; + + notes.list = []; + + notes.setNotes = function(notesList) { + notes.list = angular.copy(notesList); + }; + + return notes; +}); \ No newline at end of file diff --git a/zeppelin-web/app/views/popover-html-unsafe-popup.html b/zeppelin-web/src/components/popover-html-unsafe/popover-html-unsafe-popup.html similarity index 100% rename from zeppelin-web/app/views/popover-html-unsafe-popup.html rename to zeppelin-web/src/components/popover-html-unsafe/popover-html-unsafe-popup.html diff --git a/zeppelin-web/app/scripts/directives/popover-html-unsafe.js b/zeppelin-web/src/components/popover-html-unsafe/popover-html-unsafe.directive.js similarity index 91% rename from zeppelin-web/app/scripts/directives/popover-html-unsafe.js rename to zeppelin-web/src/components/popover-html-unsafe/popover-html-unsafe.directive.js index 8a84daaa670..3e405dcd93c 100644 --- a/zeppelin-web/app/scripts/directives/popover-html-unsafe.js +++ b/zeppelin-web/src/components/popover-html-unsafe/popover-html-unsafe.directive.js @@ -19,10 +19,10 @@ angular.module('zeppelinWebApp') restrict: 'EA', replace: true, scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' }, - templateUrl: 'views/popover-html-unsafe-popup.html' + templateUrl: 'components/popover-html-unsafe/popover-html-unsafe-popup.html' }; }) - + .directive('popoverHtmlUnsafe', ['$tooltip', function($tooltip) { return $tooltip('popoverHtmlUnsafe', 'popover', 'click'); }]); diff --git a/zeppelin-web/app/scripts/directives/resizable.js b/zeppelin-web/src/components/resizable/resizable.directive.js similarity index 100% rename from zeppelin-web/app/scripts/directives/resizable.js rename to zeppelin-web/src/components/resizable/resizable.directive.js diff --git a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js new file mode 100644 index 00000000000..2c0121090c6 --- /dev/null +++ b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js @@ -0,0 +1,66 @@ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp').factory('websocketEvents', function($rootScope, $websocket, baseUrlSrv) { + var websocketCalls = {}; + + websocketCalls.ws = $websocket(baseUrlSrv.getWebsocketProtocol() + '://' + location.hostname + ':' + baseUrlSrv.getPort()); + + websocketCalls.ws.onOpen(function() { + console.log('Websocket created'); + $rootScope.$broadcast('setConnectedStatus', true); + }); + + + websocketCalls.sendNewEvent = function(data) { + console.log('Send >> %o, %o', data.op, data); + websocketCalls.ws.send(JSON.stringify(data)); + }; + + 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 === 'NOTES_INFO') { + $rootScope.$broadcast('setNoteMenu', data.notes); + } else if (op === 'PARAGRAPH') { + $rootScope.$broadcast('updateParagraph', data); + } else if (op === 'PROGRESS') { + $rootScope.$broadcast('updateProgress', data); + } else if (op === 'COMPLETION_LIST') { + $rootScope.$broadcast('completionList', data); + } else if (op === 'ANGULAR_OBJECT_UPDATE') { + $rootScope.$broadcast('angularObjectUpdate', data); + } + }); + + websocketCalls.ws.onError(function(event) { + console.log('error message: ', event); + $rootScope.$broadcast('setConnectedStatus', false); + }); + + websocketCalls.ws.onClose(function(event) { + console.log('close message: ', event); + $rootScope.$broadcast('setConnectedStatus', false); + }); + + return websocketCalls; +}); \ No newline at end of file diff --git a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js new file mode 100644 index 00000000000..2c4f132241a --- /dev/null +++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js @@ -0,0 +1,107 @@ +/* + * 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. + */ +'use strict'; + +angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope, websocketEvents) { + + return { + + createNotebook: function() { + websocketEvents.sendNewEvent({op: 'NEW_NOTE'}); + }, + + deleteNotebook: function(noteId) { + websocketEvents.sendNewEvent({op: 'DEL_NOTE', data: {id: noteId}}); + }, + + getNotebookList: function() { + websocketEvents.sendNewEvent({op: 'LIST_NOTES'}); + }, + + getNotebook: function(noteId) { + websocketEvents.sendNewEvent({op: 'GET_NOTE', data: {id: noteId}}); + }, + + updateNotebook: function(noteId, noteName, noteConfig) { + websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config : noteConfig}}); + }, + + 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}}); + }, + + updateAngularObject: function(noteId, name, value, interpreterGroupId) { + websocketEvents.sendNewEvent({ + op: 'ANGULAR_OBJECT_UPDATED', + data: { + noteId: noteId, + name: name, + value: value, + interpreterGroupId: interpreterGroupId + } + }); + }, + + 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 + } + }); + }, + + removeParagraph: function(paragraphId) { + websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}}); + }, + + completion: function(paragraphId, buf, cursor) { + websocketEvents.sendNewEvent({ + op : 'COMPLETION', + data : { + id : paragraphId, + buf : buf, + cursor : cursor + } + }); + }, + + commitParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) { + websocketEvents.sendNewEvent({ + op: 'COMMIT_PARAGRAPH', + data: { + id: paragraphId, + title : paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + } + }); + } + + }; + +}); diff --git a/zeppelin-web/app/favicon.ico b/zeppelin-web/src/favicon.ico similarity index 100% rename from zeppelin-web/app/favicon.ico rename to zeppelin-web/src/favicon.ico diff --git a/zeppelin-web/app/fonts/FontAwesome.otf b/zeppelin-web/src/fonts/FontAwesome.otf similarity index 100% rename from zeppelin-web/app/fonts/FontAwesome.otf rename to zeppelin-web/src/fonts/FontAwesome.otf diff --git a/zeppelin-web/app/fonts/Simple-Line-Icons.eot b/zeppelin-web/src/fonts/Simple-Line-Icons.eot similarity index 100% rename from zeppelin-web/app/fonts/Simple-Line-Icons.eot rename to zeppelin-web/src/fonts/Simple-Line-Icons.eot diff --git a/zeppelin-web/app/fonts/Simple-Line-Icons.svg b/zeppelin-web/src/fonts/Simple-Line-Icons.svg similarity index 100% rename from zeppelin-web/app/fonts/Simple-Line-Icons.svg rename to zeppelin-web/src/fonts/Simple-Line-Icons.svg diff --git a/zeppelin-web/app/fonts/Simple-Line-Icons.ttf b/zeppelin-web/src/fonts/Simple-Line-Icons.ttf similarity index 100% rename from zeppelin-web/app/fonts/Simple-Line-Icons.ttf rename to zeppelin-web/src/fonts/Simple-Line-Icons.ttf diff --git a/zeppelin-web/app/fonts/Simple-Line-Icons.woff b/zeppelin-web/src/fonts/Simple-Line-Icons.woff similarity index 100% rename from zeppelin-web/app/fonts/Simple-Line-Icons.woff rename to zeppelin-web/src/fonts/Simple-Line-Icons.woff diff --git a/zeppelin-web/app/styles/custom-font.css b/zeppelin-web/src/fonts/custom-font.css similarity index 100% rename from zeppelin-web/app/styles/custom-font.css rename to zeppelin-web/src/fonts/custom-font.css diff --git a/zeppelin-web/app/fonts/custom-font.eot b/zeppelin-web/src/fonts/custom-font.eot similarity index 100% rename from zeppelin-web/app/fonts/custom-font.eot rename to zeppelin-web/src/fonts/custom-font.eot diff --git a/zeppelin-web/app/fonts/custom-font.svg b/zeppelin-web/src/fonts/custom-font.svg similarity index 100% rename from zeppelin-web/app/fonts/custom-font.svg rename to zeppelin-web/src/fonts/custom-font.svg diff --git a/zeppelin-web/app/fonts/custom-font.ttf b/zeppelin-web/src/fonts/custom-font.ttf similarity index 100% rename from zeppelin-web/app/fonts/custom-font.ttf rename to zeppelin-web/src/fonts/custom-font.ttf diff --git a/zeppelin-web/app/fonts/custom-font.woff b/zeppelin-web/src/fonts/custom-font.woff similarity index 100% rename from zeppelin-web/app/fonts/custom-font.woff rename to zeppelin-web/src/fonts/custom-font.woff diff --git a/zeppelin-web/app/styles/font-awesome.min.css b/zeppelin-web/src/fonts/font-awesome.min.css similarity index 100% rename from zeppelin-web/app/styles/font-awesome.min.css rename to zeppelin-web/src/fonts/font-awesome.min.css diff --git a/zeppelin-web/app/fonts/fontawesome-webfont.eot b/zeppelin-web/src/fonts/fontawesome-webfont.eot similarity index 100% rename from zeppelin-web/app/fonts/fontawesome-webfont.eot rename to zeppelin-web/src/fonts/fontawesome-webfont.eot diff --git a/zeppelin-web/app/fonts/fontawesome-webfont.svg b/zeppelin-web/src/fonts/fontawesome-webfont.svg similarity index 100% rename from zeppelin-web/app/fonts/fontawesome-webfont.svg rename to zeppelin-web/src/fonts/fontawesome-webfont.svg diff --git a/zeppelin-web/app/fonts/fontawesome-webfont.ttf b/zeppelin-web/src/fonts/fontawesome-webfont.ttf similarity index 100% rename from zeppelin-web/app/fonts/fontawesome-webfont.ttf rename to zeppelin-web/src/fonts/fontawesome-webfont.ttf diff --git a/zeppelin-web/app/fonts/fontawesome-webfont.woff b/zeppelin-web/src/fonts/fontawesome-webfont.woff similarity index 100% rename from zeppelin-web/app/fonts/fontawesome-webfont.woff rename to zeppelin-web/src/fonts/fontawesome-webfont.woff diff --git a/zeppelin-web/app/styles/simple-line-icons.css b/zeppelin-web/src/fonts/simple-line-icons.css similarity index 100% rename from zeppelin-web/app/styles/simple-line-icons.css rename to zeppelin-web/src/fonts/simple-line-icons.css diff --git a/zeppelin-web/app/index.html b/zeppelin-web/src/index.html similarity index 56% rename from zeppelin-web/app/index.html rename to zeppelin-web/src/index.html index 4d0ff089a35..5676afac591 100644 --- a/zeppelin-web/app/index.html +++ b/zeppelin-web/src/index.html @@ -3,7 +3,7 @@ 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 +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, @@ -40,69 +40,31 @@ - - - - - - - - + + + + + + - + - +

You are using an outdated browser. Please upgrade your browser to improve your experience.

+ +
-
+
+ + + @@ -117,7 +79,7 @@ - + @@ -137,20 +99,26 @@ + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index ecdefd4796d..6934791f83a 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -386,7 +386,7 @@ public static enum ConfVars { ZEPPELIN_SSL_TRUSTSTORE_PATH("zeppelin.ssl.truststore.path", null), ZEPPELIN_SSL_TRUSTSTORE_TYPE("zeppelin.ssl.truststore.type", null), ZEPPELIN_SSL_TRUSTSTORE_PASSWORD("zeppelin.ssl.truststore.password", null), - ZEPPELIN_WAR("zeppelin.war", "../zeppelin-web/src/main/webapp"), + ZEPPELIN_WAR("zeppelin.war", "../zeppelin-web/dist"), ZEPPELIN_API_WAR("zeppelin.api.war", "../zeppelin-docs/src/main/swagger"), ZEPPELIN_INTERPRETERS("zeppelin.interpreters", "org.apache.zeppelin.spark.SparkInterpreter," + "org.apache.zeppelin.spark.PySparkInterpreter,"