mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Fix project after git clean
This commit is contained in:
parent
9b249eab2c
commit
92013605b4
8 changed files with 3255 additions and 12 deletions
22
.gitignore
vendored
22
.gitignore
vendored
|
|
@ -24,16 +24,18 @@ zeppelin-web/bower_components
|
|||
**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/
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<warSourceDirectory>dist</warSourceDirectory>
|
||||
<webXml>dist\WEB-INF\web.xml</webXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
|||
|
|
@ -113,11 +113,11 @@ angular
|
|||
templateUrl: 'app/home/home.html'
|
||||
})
|
||||
.when('/notebook/:noteId', {
|
||||
templateUrl: 'app/notebook/notebooks.html',
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/notebook/:noteId/paragraph/:paragraphId?', {
|
||||
templateUrl: 'app/notebook/notebooks.html',
|
||||
templateUrl: 'app/notebook/notebook.html',
|
||||
controller: 'NotebookCtrl'
|
||||
})
|
||||
.when('/interpreter', {
|
||||
|
|
|
|||
494
zeppelin-web/src/app/notebook/notebook.controller.js
Normal file
494
zeppelin-web/src/app/notebook/notebook.controller.js
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
/* 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:NotebookCtrl
|
||||
* @description
|
||||
* # NotebookCtrl
|
||||
* Controller of notes, manage the note (update)
|
||||
*
|
||||
*/
|
||||
angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $route, $routeParams, $location, $rootScope, $http) {
|
||||
$scope.note = null;
|
||||
$scope.showEditor = false;
|
||||
$scope.editorToggled = false;
|
||||
$scope.tableToggled = false;
|
||||
$scope.viewOnly = false;
|
||||
$scope.looknfeelOption = [ 'default', 'simple', 'report'];
|
||||
$scope.cronOption = [
|
||||
{name: 'None', value : undefined},
|
||||
{name: '1m', value: '0 0/1 * * * ?'},
|
||||
{name: '5m', value: '0 0/5 * * * ?'},
|
||||
{name: '1h', value: '0 0 0/1 * * ?'},
|
||||
{name: '3h', value: '0 0 0/3 * * ?'},
|
||||
{name: '6h', value: '0 0 0/6 * * ?'},
|
||||
{name: '12h', value: '0 0 0/12 * * ?'},
|
||||
{name: '1d', value: '0 0 0 * * ?'}
|
||||
];
|
||||
|
||||
$scope.interpreterSettings = [];
|
||||
$scope.interpreterBindings = [];
|
||||
|
||||
var angularObjectRegistry = {};
|
||||
|
||||
$scope.getCronOptionNameFromValue = function(value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
for (var o in $scope.cronOption) {
|
||||
if ($scope.cronOption[o].value===value) {
|
||||
return $scope.cronOption[o].name;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/** Init the new controller */
|
||||
var initNotebook = function() {
|
||||
$rootScope.$emit('sendNewEvent', {op: 'GET_NOTE', data: {id: $routeParams.noteId}});
|
||||
};
|
||||
|
||||
initNotebook();
|
||||
|
||||
/** Remove the note and go back tot he main page */
|
||||
/** TODO(anthony): In the nearly future, go back to the main page and telle to the dude that the note have been remove */
|
||||
$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}});
|
||||
$location.path('/#');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.runNote = function() {
|
||||
var result = confirm('Run all paragraphs?');
|
||||
if (result) {
|
||||
$scope.$broadcast('runParagraph');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleAllEditor = function() {
|
||||
if ($scope.editorToggled) {
|
||||
$scope.$broadcast('closeEditor');
|
||||
} else {
|
||||
$scope.$broadcast('openEditor');
|
||||
}
|
||||
$scope.editorToggled = !$scope.editorToggled;
|
||||
};
|
||||
|
||||
$scope.showAllEditor = function() {
|
||||
$scope.$broadcast('openEditor');
|
||||
};
|
||||
|
||||
$scope.hideAllEditor = function() {
|
||||
$scope.$broadcast('closeEditor');
|
||||
};
|
||||
|
||||
$scope.toggleAllTable = function() {
|
||||
if ($scope.tableToggled) {
|
||||
$scope.$broadcast('closeTable');
|
||||
} else {
|
||||
$scope.$broadcast('openTable');
|
||||
}
|
||||
$scope.tableToggled = !$scope.tableToggled;
|
||||
};
|
||||
|
||||
$scope.showAllTable = function() {
|
||||
$scope.$broadcast('openTable');
|
||||
};
|
||||
|
||||
$scope.hideAllTable = function() {
|
||||
$scope.$broadcast('closeTable');
|
||||
};
|
||||
|
||||
$scope.isNoteRunning = function() {
|
||||
var running = false;
|
||||
if(!$scope.note){ return false; }
|
||||
for (var i=0; i<$scope.note.paragraphs.length; i++) {
|
||||
if ( $scope.note.paragraphs[i].status === 'PENDING' || $scope.note.paragraphs[i].status === 'RUNNING') {
|
||||
running = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return running;
|
||||
};
|
||||
|
||||
$scope.setLookAndFeel = function(looknfeel) {
|
||||
$scope.note.config.looknfeel = looknfeel;
|
||||
$scope.setConfig();
|
||||
};
|
||||
|
||||
/** Set cron expression for this note **/
|
||||
$scope.setCronScheduler = function(cronExpr) {
|
||||
$scope.note.config.cron = cronExpr;
|
||||
$scope.setConfig();
|
||||
};
|
||||
|
||||
/** Update note config **/
|
||||
$scope.setConfig = function(config) {
|
||||
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}});
|
||||
};
|
||||
|
||||
/** 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}});
|
||||
}
|
||||
};
|
||||
|
||||
/** update the current note */
|
||||
$scope.$on('setNoteContent', function(event, note) {
|
||||
$scope.paragraphUrl = $routeParams.paragraphId;
|
||||
$scope.asIframe = $routeParams.asIframe;
|
||||
if ($scope.paragraphUrl) {
|
||||
note = cleanParagraphExcept($scope.paragraphUrl, note);
|
||||
$rootScope.$emit('setIframe', $scope.asIframe);
|
||||
}
|
||||
|
||||
if ($scope.note === null) {
|
||||
$scope.note = note;
|
||||
} else {
|
||||
updateNote(note);
|
||||
}
|
||||
initializeLookAndFeel();
|
||||
//open interpreter binding setting when there're none selected
|
||||
getInterpreterBindings(getInterpreterBindingsCallBack);
|
||||
});
|
||||
|
||||
|
||||
var initializeLookAndFeel = function() {
|
||||
if (!$scope.note.config.looknfeel) {
|
||||
$scope.note.config.looknfeel = 'default';
|
||||
} else {
|
||||
$scope.viewOnly = $scope.note.config.looknfeel === 'report' ? true : false;
|
||||
}
|
||||
$rootScope.$emit('setLookAndFeel', $scope.note.config.looknfeel);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var cleanParagraphExcept = function(paragraphId, note) {
|
||||
var noteCopy = {};
|
||||
noteCopy.id = note.id;
|
||||
noteCopy.name = note.name;
|
||||
noteCopy.config = note.config;
|
||||
noteCopy.info = note.info;
|
||||
noteCopy.paragraphs = [];
|
||||
for (var i=0; i<note.paragraphs.length; i++) {
|
||||
if (note.paragraphs[i].id === paragraphId) {
|
||||
noteCopy.paragraphs[0] = note.paragraphs[i];
|
||||
if (!noteCopy.paragraphs[0].config) {
|
||||
noteCopy.paragraphs[0].config = {};
|
||||
}
|
||||
noteCopy.paragraphs[0].config.editorHide = true;
|
||||
noteCopy.paragraphs[0].config.tableHide = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return noteCopy;
|
||||
};
|
||||
|
||||
$scope.$on('moveParagraphUp', function(event, paragraphId) {
|
||||
var newIndex = -1;
|
||||
for (var i=0; i<$scope.note.paragraphs.length; i++) {
|
||||
if ($scope.note.paragraphs[i].id === paragraphId) {
|
||||
newIndex = i-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
|
||||
return;
|
||||
}
|
||||
$rootScope.$emit('sendNewEvent', { op: 'MOVE_PARAGRAPH', data : {id: paragraphId, index: newIndex}});
|
||||
});
|
||||
|
||||
// create new paragraph on current position
|
||||
$scope.$on('insertParagraph', function(event, paragraphId) {
|
||||
var newIndex = -1;
|
||||
for (var i=0; i<$scope.note.paragraphs.length; i++) {
|
||||
if ($scope.note.paragraphs[i].id === paragraphId) {
|
||||
newIndex = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newIndex === $scope.note.paragraphs.length) {
|
||||
alert('Cannot insert after the last paragraph.');
|
||||
return;
|
||||
}
|
||||
if (newIndex < 0 || newIndex > $scope.note.paragraphs.length) {
|
||||
return;
|
||||
}
|
||||
$rootScope.$emit('sendNewEvent', { op: 'INSERT_PARAGRAPH', data : {index: newIndex}});
|
||||
});
|
||||
|
||||
$scope.$on('moveParagraphDown', function(event, paragraphId) {
|
||||
var newIndex = -1;
|
||||
for (var i=0; i<$scope.note.paragraphs.length; i++) {
|
||||
if ($scope.note.paragraphs[i].id === paragraphId) {
|
||||
newIndex = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
|
||||
return;
|
||||
}
|
||||
$rootScope.$emit('sendNewEvent', { op: 'MOVE_PARAGRAPH', data : {id: paragraphId, index: newIndex}});
|
||||
});
|
||||
|
||||
$scope.$on('moveFocusToPreviousParagraph', function(event, currentParagraphId){
|
||||
var focus = false;
|
||||
for (var i=$scope.note.paragraphs.length-1; i>=0; i--) {
|
||||
if (focus === false ) {
|
||||
if ($scope.note.paragraphs[i].id === currentParagraphId) {
|
||||
focus = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
var p = $scope.note.paragraphs[i];
|
||||
if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
|
||||
$scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('moveFocusToNextParagraph', function(event, currentParagraphId){
|
||||
var focus = false;
|
||||
for (var i=0; i<$scope.note.paragraphs.length; i++) {
|
||||
if (focus === false ) {
|
||||
if ($scope.note.paragraphs[i].id === currentParagraphId) {
|
||||
focus = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
var p = $scope.note.paragraphs[i];
|
||||
if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
|
||||
$scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var updateNote = function(note) {
|
||||
/** update Note name */
|
||||
if (note.name !== $scope.note.name) {
|
||||
console.log('change note name: %o to %o', $scope.note.name, note.name);
|
||||
$scope.note.name = note.name;
|
||||
}
|
||||
|
||||
$scope.note.config = note.config;
|
||||
$scope.note.info = note.info;
|
||||
|
||||
var newParagraphIds = note.paragraphs.map(function(x) {return x.id;});
|
||||
var oldParagraphIds = $scope.note.paragraphs.map(function(x) {return x.id;});
|
||||
|
||||
var numNewParagraphs = newParagraphIds.length;
|
||||
var numOldParagraphs = oldParagraphIds.length;
|
||||
|
||||
/** add a new paragraph */
|
||||
if (numNewParagraphs > numOldParagraphs) {
|
||||
for (var index in newParagraphIds) {
|
||||
if (oldParagraphIds[index] !== newParagraphIds[index]) {
|
||||
$scope.note.paragraphs.splice(index, 0, note.paragraphs[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** update or move paragraph */
|
||||
if (numNewParagraphs === numOldParagraphs) {
|
||||
for (var idx in newParagraphIds) {
|
||||
var newEntry = note.paragraphs[idx];
|
||||
if (oldParagraphIds[idx] === newParagraphIds[idx]) {
|
||||
$scope.$broadcast('updateParagraph', {paragraph: newEntry});
|
||||
} else {
|
||||
// move paragraph
|
||||
var oldIdx = oldParagraphIds.indexOf(newParagraphIds[idx]);
|
||||
$scope.note.paragraphs.splice(oldIdx, 1);
|
||||
$scope.note.paragraphs.splice(idx, 0, newEntry);
|
||||
// rebuild id list since paragraph has moved.
|
||||
oldParagraphIds = $scope.note.paragraphs.map(function(x) {return x.id;});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** remove paragraph */
|
||||
if (numNewParagraphs < numOldParagraphs) {
|
||||
for (var oldidx in oldParagraphIds) {
|
||||
if(oldParagraphIds[oldidx] !== newParagraphIds[oldidx]) {
|
||||
$scope.note.paragraphs.splice(oldidx, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var getInterpreterBindings = function(callback) {
|
||||
$http.get(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
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
var getInterpreterBindingsCallBack = function() {
|
||||
var selected = false;
|
||||
for (var i in $scope.interpreterBindings) {
|
||||
var setting = $scope.interpreterBindings[i];
|
||||
if (setting.selected) {
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selected) {
|
||||
// make default selection
|
||||
var selectedIntp = {};
|
||||
for (var i in $scope.interpreterBindings) {
|
||||
var setting = $scope.interpreterBindings[i];
|
||||
if (!selectedIntp[setting.group]) {
|
||||
setting.selected = true;
|
||||
selectedIntp[setting.group] = true;
|
||||
}
|
||||
}
|
||||
$scope.showSetting = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.interpreterSelectionListeners = {
|
||||
accept : function(sourceItemHandleScope, destSortableScope) {return true;},
|
||||
itemMoved: function (event) {},
|
||||
orderChanged: function(event) {}
|
||||
};
|
||||
|
||||
$scope.openSetting = function() {
|
||||
$scope.showSetting = true;
|
||||
getInterpreterBindings();
|
||||
};
|
||||
|
||||
$scope.closeSetting = function() {
|
||||
if (isSettingDirty()) {
|
||||
var result = confirm('Changes will be discarded');
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$scope.showSetting = false;
|
||||
};
|
||||
|
||||
$scope.saveSetting = function() {
|
||||
var selectedSettingIds = [];
|
||||
for (var no in $scope.interpreterBindings) {
|
||||
var setting = $scope.interpreterBindings[no];
|
||||
if (setting.selected) {
|
||||
selectedSettingIds.push(setting.id);
|
||||
}
|
||||
}
|
||||
|
||||
$http.put(getRestApiBase() + '/notebook/interpreter/bind/' + $scope.note.id,
|
||||
selectedSettingIds).
|
||||
success(function(data, status, headers, config) {
|
||||
console.log('Interpreter binding %o saved', selectedSettingIds);
|
||||
$scope.showSetting = false;
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
console.log('Error %o %o', status, data.message);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleSetting = function() {
|
||||
if ($scope.showSetting) {
|
||||
$scope.closeSetting();
|
||||
} else {
|
||||
$scope.openSetting();
|
||||
}
|
||||
};
|
||||
|
||||
var isSettingDirty = function() {
|
||||
if (angular.equals($scope.interpreterBindings, $scope.interpreterBindingsOrig)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on('angularObjectUpdate', function(event, data) {
|
||||
if (data.noteId === $scope.note.id) {
|
||||
var scope = $rootScope.compiledScope;
|
||||
var varName = data.angularObject.name;
|
||||
|
||||
if (angular.equals(data.angularObject.object, scope[varName])) {
|
||||
// return when update has no change
|
||||
return;
|
||||
}
|
||||
|
||||
if (!angularObjectRegistry[varName]) {
|
||||
angularObjectRegistry[varName] = {
|
||||
interpreterGroupId : data.interpreterGroupId,
|
||||
}
|
||||
}
|
||||
|
||||
angularObjectRegistry[varName].skipEmit = true;
|
||||
|
||||
if (!angularObjectRegistry[varName].clearWatcher) {
|
||||
angularObjectRegistry[varName].clearWatcher = scope.$watch(varName, function(newValue, oldValue) {
|
||||
if (angularObjectRegistry[varName].skipEmit) {
|
||||
angularObjectRegistry[varName].skipEmit = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$rootScope.$emit('sendNewEvent', {
|
||||
op: 'ANGULAR_OBJECT_UPDATED',
|
||||
data: {
|
||||
noteId: $routeParams.noteId,
|
||||
name:varName,
|
||||
value:newValue,
|
||||
interpreterGroupId:angularObjectRegistry[varName].interpreterGroupId
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
scope[varName] = data.angularObject.object;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var isFunction = function(functionToCheck) {
|
||||
var getType = {};
|
||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||
}
|
||||
|
||||
});
|
||||
508
zeppelin-web/src/app/notebook/notebook.css
Normal file
508
zeppelin-web/src/app/notebook/notebook.css
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.paragraph-col {
|
||||
margin: 0 0 0 0px;
|
||||
padding: 0 0 0 0px;
|
||||
}
|
||||
|
||||
.paragraph {
|
||||
padding: 2px 8px 4px 8px;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.paragraph .tableDisplay .hljs {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.paragraph .ace_print-margin {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.paragraphAsIframe{
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin-top: -79px;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.paragraphAsIframe .control {
|
||||
background-color: rgba(255,255,255,0.9);
|
||||
border-top: 1px solid #EFEFEF;
|
||||
display: none;
|
||||
float: right;
|
||||
color: #999;
|
||||
margin-top: -9px;
|
||||
margin-right:0px;
|
||||
position:absolute;
|
||||
clear:both;
|
||||
right:25px;
|
||||
/*z-index:10;*/
|
||||
}
|
||||
|
||||
.paragraphAsIframe table {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.paragraphAsIframe .editor {
|
||||
width: 100%;
|
||||
border-left: 4px solid #EEEEEE;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.paragraphAsIframe .text {
|
||||
white-space: pre;
|
||||
display: block;
|
||||
unicode-bidi: embed;
|
||||
display: block !important;
|
||||
margin: 0 0 10px!important;
|
||||
font-size: 12px!important;
|
||||
line-height: 1.42857143!important;
|
||||
word-break: break-all!important;
|
||||
word-wrap: break-word!important;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selection {
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.ace_marker-layer .ace_selected-word {
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.labelBtn {
|
||||
padding: .2em .6em .3em;
|
||||
font-size: 75%;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
border-radius: .25em;
|
||||
}
|
||||
|
||||
.note-jump {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.noteBtnfa {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.control span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.control {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.paragraph-space {
|
||||
margin-bottom: 5px;
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.paragraph .control {
|
||||
background-color: rgba(255,255,255,0.85);
|
||||
/*display: none;*/
|
||||
float: right;
|
||||
color: #999;
|
||||
margin-top: 1px;
|
||||
margin-right: 5px;
|
||||
position:absolute;
|
||||
clear:both;
|
||||
right:15px;
|
||||
top: 16px;
|
||||
text-align:right;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.paragraph .control li{
|
||||
font-size:12px;
|
||||
margin-bottom:4px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.paragraph table {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.paragraph .title {
|
||||
margin: 3px 0px 0px 0px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.paragraph .title div {
|
||||
width: 80%;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 17px !important;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.paragraph .title input {
|
||||
width: 80%;
|
||||
line-height: 1.42857143;
|
||||
color: #555;
|
||||
background-color: #fff;
|
||||
background-image: none;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 0px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
text-transform: capitalize;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px!important;
|
||||
}
|
||||
|
||||
.paragraph .editor {
|
||||
width: 100%;
|
||||
border-left: 4px solid #DDDDDD;
|
||||
background: rgba(255, 255, 255, 0.0);
|
||||
margin: 7px 0 2px 0px;
|
||||
}
|
||||
|
||||
.paragraph .text {
|
||||
white-space: pre;
|
||||
display: block;
|
||||
unicode-bidi: embed;
|
||||
display: block !important;
|
||||
margin: 0 0 0px !important;
|
||||
line-height: 1.42857143 !important;
|
||||
word-break: break-all !important;
|
||||
word-wrap: break-word !important;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
font-size: 12px !important;
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.paragraph p {
|
||||
margin : 0 0 0 0px;
|
||||
}
|
||||
|
||||
.paragraph div svg {
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
.ace-tm {
|
||||
background-color: #FFFFFF;
|
||||
color: black;
|
||||
}
|
||||
.ace_editor {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
|
||||
font-size: 12px;
|
||||
line-height: normal;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.ace_hidden-cursors {opacity:0}
|
||||
|
||||
/** Remove z-index to ace */
|
||||
.ace_text-input, .ace_gutter, .ace_layer,
|
||||
.emacs-mode, .ace_text-layer, .ace_cursor-layer,
|
||||
.ace_cursor, .ace_scrollbar {
|
||||
z-index:auto !important;
|
||||
}
|
||||
|
||||
/** Force opacity:0 to textarea in writing texts **/
|
||||
.ace_text-input.ace_composition {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
#main .emacs-mode .ace_cursor {
|
||||
background-color:#C0C0C0!important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.paragraph .status {
|
||||
font-size: 10px;
|
||||
color: #AAAAAA;
|
||||
text-align: right;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.paragraph .runControl {
|
||||
font-size: 1px;
|
||||
color: #AAAAAA;
|
||||
height:4px;
|
||||
margin: 1px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.paragraph .runControl .progress {
|
||||
position: relative;
|
||||
width:100%;
|
||||
height:4px;
|
||||
z-index:100;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.paragraph .runControl .progress .progress-bar {
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
.paragraph .executionTime {
|
||||
color: #999;
|
||||
font-size: 10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.disable {
|
||||
opacity:0.4!important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.noteAction {
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
margin-top: -10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
.noteAction li{
|
||||
font-size:12px;
|
||||
margin-bottom:4px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.new_h3 {
|
||||
margin-top: 1px;
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.form-control2 {
|
||||
width: 100%;
|
||||
margin-left: 15px;
|
||||
font-size: 29px;
|
||||
line-height: 1.42857143;
|
||||
color: #555;
|
||||
background-color: #fff;
|
||||
background-image: none;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
}
|
||||
|
||||
.form-control-static2 {
|
||||
padding-top: 7px;
|
||||
font-size: 29px;
|
||||
margin-left: 15px;
|
||||
padding-bottom: 7px;
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* panel default */
|
||||
.panel-default {
|
||||
/* border: none; */
|
||||
border-color: #DDDDDD;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.panel-group .panel-default {
|
||||
/*border: solid #e5e5e5;
|
||||
border-width: 1px 1px 2px;*/
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading {
|
||||
color: #34495e;
|
||||
background-color: #ffffff;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading + .panel-collapse .panel-body {
|
||||
border-top-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading > .dropdown .caret {
|
||||
border-color: #ecf0f1 transparent;
|
||||
}
|
||||
|
||||
.panel-default > .panel-footer + .panel-collapse .panel-body {
|
||||
border-bottom-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.panel-body-heading {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-left: 10px;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.paragraph-margin {
|
||||
margin-right: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.tableDisplay img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.tableDisplay .btn-group span {
|
||||
margin: 10px 0px 0px 10px;
|
||||
font-size:12px;
|
||||
}
|
||||
.tableDisplay .btn-group span a {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.tableDisplay .option {
|
||||
padding: 5px 5px 5px 5px;
|
||||
font-size:12px;
|
||||
height:auto;
|
||||
overflow : auto;
|
||||
/*min-height: 200px;*/
|
||||
border-top: 1px solid #ecf0f1;
|
||||
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns ul {
|
||||
|
||||
background-color: white;
|
||||
/*min-width: 100px;*/
|
||||
width:auto;
|
||||
padding: 3px 3px 3px 3px;
|
||||
height : 150px;
|
||||
border: 1px solid #CCC;
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
|
||||
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
|
||||
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns ul li {
|
||||
margin: 3px 3px 3px 3px;
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns ul li span {
|
||||
cursor: pointer;
|
||||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns ul li div ul { /* aggregation menu */
|
||||
width:auto;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns ul li div ul li a {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tableDisplay .option .columns a:focus,
|
||||
.tableDisplay .option .columns a:hover {
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
outline-offset: 0px;
|
||||
}
|
||||
|
||||
.graphContainer {
|
||||
position:relative;
|
||||
margin-bottom: 5px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.noOverflow {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.graphContainer .table {
|
||||
overflow: hidden;
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.allFields {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.noDot {
|
||||
list-style-type: none;
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
.liVertical {
|
||||
display:block;
|
||||
float:left;
|
||||
padding: 5px;
|
||||
}
|
||||
.row {
|
||||
margin-right: 0px !important
|
||||
}
|
||||
|
||||
.lightBold {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.resizable-helper {
|
||||
border: 3px solid #DDDDDD;
|
||||
}
|
||||
|
||||
/* note setting panel */
|
||||
.setting {
|
||||
background-color: white;
|
||||
padding: 10px 15px 15px 15px;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.setting .interpreterSettings {
|
||||
list-style-type: none;
|
||||
background-color: #EFEFEF;
|
||||
padding: 10px 10px 10px 10px;
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.15);
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.setting .interpreterSettings div div {
|
||||
margin: 2px 0px 2px 0px;
|
||||
}
|
||||
|
||||
.setting .interpreterSettings div div {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.setting .modal-header {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.setting .modal-body {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.setting .modal-footer {
|
||||
border: 0px;
|
||||
}
|
||||
170
zeppelin-web/src/app/notebook/notebook.html
Normal file
170
zeppelin-web/src/app/notebook/notebook.html
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<!-- Here the controller <NotebookCtrl> is not needed because explicitly set in the app.js (route) -->
|
||||
<div>
|
||||
<div class="noteAction" ng-show="note.id && !paragraphUrl">
|
||||
<h3 class="new_h3">
|
||||
<input type="text" class="form-control2" placeholder="{{note.name || 'Note ' + note.id}}" style="width:200px;"
|
||||
ng-show="showEditor" ng-model="note.name" ng-enter="sendNewName()" ng-delete="showEditor = false" autofocus/>
|
||||
<p class="form-control-static2" ng-click="showEditor = true" ng-show="!showEditor">{{note.name || 'Note ' + note.id}}</p>
|
||||
<span class="labelBtn btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-click="runNote()"
|
||||
ng-if="!isNoteRunning()"
|
||||
tooltip-placement="top" tooltip="Run all the note">
|
||||
<i class="icon-control-play"></i>
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-click="toggleAllEditor()"
|
||||
ng-hide="viewOnly"
|
||||
tooltip-placement="top" tooltip="Show/hide the code">
|
||||
<i ng-class="editorToggled ? 'fa icon-size-actual' : 'fa icon-size-fullscreen'"></i></button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-click="toggleAllTable()"
|
||||
ng-hide="viewOnly"
|
||||
tooltip-placement="top" tooltip="Show/hide the output">
|
||||
<i ng-class="tableToggled ? 'fa icon-notebook' : 'fa icon-book-open'"></i></button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-click="removeNote(note.id)"
|
||||
ng-hide="viewOnly"
|
||||
tooltip-placement="top" tooltip="Remove the notebook">
|
||||
<i class="icon-trash"></i></button>
|
||||
</span>
|
||||
|
||||
<span ng-hide="viewOnly">
|
||||
<div class="labelBtn btn-group">
|
||||
<div class="btn btn-default btn-xs dropdown-toggle"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
ng-class="{ 'btn-info' : note.config.cron, 'btn-danger' : note.info.cron, 'btn-default' : !note.config.cron}">
|
||||
<span class="fa fa-clock-o"></span> {{getCronOptionNameFromValue(note.config.cron)}}
|
||||
</div>
|
||||
<ul class="dropdown-menu" role="menu" style="width:300px">
|
||||
<li>
|
||||
<div style="padding:10px 20px 0 20px;font-weight:normal;word-wrap:break-word">
|
||||
Run note with cron scheduler.
|
||||
Either choose from<br/>preset or write your own <a href="http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger" target=_blank>cron expression</a>.
|
||||
<br/><br/>
|
||||
<span>- Preset</span>
|
||||
<a ng-repeat="cr in cronOption"
|
||||
type="button"
|
||||
ng-click="setCronScheduler(cr.value)"
|
||||
style="cursor:pointer"
|
||||
dropdown-input>{{cr.name}}</a>
|
||||
<br/><br/>
|
||||
<span>- Cron expression</span>
|
||||
<input type="text"
|
||||
ng-model="note.config.cron"
|
||||
ng-change="setCronScheduler(note.config.cron)"
|
||||
dropdown-input>
|
||||
</input>
|
||||
<p ng-show="note.info.cron"
|
||||
style="color:red">
|
||||
{{note.info.cron}}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div class="pull-right"
|
||||
style="margin-top:15px; margin-right:15px; font-size:15px;">
|
||||
<span style="position:relative; top:3px; margin-right:4px; cursor:pointer"
|
||||
data-toggle="modal"
|
||||
data-target="#shortcutModal"
|
||||
tooltip-placement="top" tooltip="List of shortcut">
|
||||
<i class="icon-question"></i>
|
||||
</span>
|
||||
<span style="position:relative; top:2px; margin-right:4px; cursor:pointer;"
|
||||
ng-click="toggleSetting()"
|
||||
tooltip-placement="top" tooltip="Interpreter binding">
|
||||
<i class="fa fa-cog"
|
||||
ng-style="{color: showSetting ? '#3071A9' : 'black' }"></i>
|
||||
</span>
|
||||
|
||||
<span class="btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs dropdown-toggle"
|
||||
data-toggle="dropdown">
|
||||
{{note.config.looknfeel}} <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li ng-repeat="looknfeel in looknfeelOption">
|
||||
<a style="cursor:pointer"
|
||||
ng-click="setLookAndFeel(looknfeel)">{{looknfeel}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<!-- settings -->
|
||||
<div ng-show="showSetting"
|
||||
class="setting">
|
||||
<div>
|
||||
<h4>Settings</h4>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<h5>Interpreter binding</h5>
|
||||
<p>
|
||||
Bind interpreter for this note.
|
||||
Click to Bind/Unbind interpreter.
|
||||
Drag and drop to reorder interpreters. <br />
|
||||
The first interpreter on the list becomes default. To create/remove interpreters, go to <a href="/#/interpreter">Interpreter</a> menu.
|
||||
</p>
|
||||
|
||||
<div class="interpreterSettings"
|
||||
as-sortable="interpreterSelectionListeners" data-ng-model="interpreterBindings">
|
||||
<div data-ng-repeat="item in interpreterBindings" as-sortable-item>
|
||||
<div as-sortable-item-handle
|
||||
ng-click="item.selected = !item.selected"
|
||||
class="btn"
|
||||
ng-class="{'btn-info': item.selected, 'btn-default': !item.selected}"><font style="font-size:16px">{{item.name}}</font> <small><span ng-repeat="intp in item.interpreters"><span ng-show="!$first">, </span>%{{intp.name}}</span></small></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn btn-primary" ng-click="saveSetting()">Save</button>
|
||||
<button class="btn btn-default" ng-click="closeSetting()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note-jump"></div>
|
||||
|
||||
<!-- Include the paragraphs according to the note -->
|
||||
<div id="{{currentParagraph.id}}_paragraphColumn_main"
|
||||
ng-repeat="currentParagraph in note.paragraphs"
|
||||
ng-controller="ParagraphCtrl"
|
||||
ng-Init="init(currentParagraph)"
|
||||
ng-class="columnWidthClass(currentParagraph.config.colWidth)"
|
||||
class="paragraph-col">
|
||||
<div id="{{currentParagraph.id}}_paragraphColumn"
|
||||
ng-include src="'app/notebook/paragraph/paragraph.html'"
|
||||
ng-class="{'paragraph-space box paragraph-margin': !asIframe, 'focused': paragraphFocused}"
|
||||
ng-hide="currentParagraph.config.tableHide && viewOnly">
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear:both;height:10px"></div>
|
||||
</div>
|
||||
1619
zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
Normal file
1619
zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
Normal file
File diff suppressed because it is too large
Load diff
449
zeppelin-web/src/app/notebook/paragraph/paragraph.html
Normal file
449
zeppelin-web/src/app/notebook/paragraph/paragraph.html
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
<!--
|
||||
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="{{paragraph.id}}_container"
|
||||
ng-class="{'paragraph outlineOnFocus': !asIframe, 'paragraphAsIframe': asIframe}">
|
||||
|
||||
<div ng-show="paragraph.config.title"
|
||||
id="{{paragraph.id}}_title"
|
||||
class="title">
|
||||
<input type="text"
|
||||
placeholder="Edit title"
|
||||
ng-model="paragraph.title"
|
||||
ng-show="showTitleEditor"
|
||||
ng-delete="showTitleEditor = false"
|
||||
ng-enter="setTitle(); showTitleEditor = false"/>
|
||||
<div ng-click="showTitleEditor = !asIframe && !viewOnly"
|
||||
ng-show="!showTitleEditor"
|
||||
ng-bind-html="paragraph.title || 'Untitled'">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div ng-show="!paragraph.config.editorHide">
|
||||
<div id="{{paragraph.id}}_editor"
|
||||
style="opacity: 1;"
|
||||
class="editor"
|
||||
ui-ace="{
|
||||
onLoad : aceLoaded,
|
||||
onChange: aceChanged,
|
||||
require : ['ace/ext/language_tools']
|
||||
}"
|
||||
ng-model="paragraph.text"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="{{paragraph.id}}_runControl" class="runControl">
|
||||
<div ng-if="(getProgress()<=0 || getProgress()>=100) && (paragraph.status=='RUNNING' )">
|
||||
<div id="{{paragraph.id}}_progress"
|
||||
class="progress">
|
||||
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width:100%;"></div>
|
||||
<span class="sr-only"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="getProgress()>0 && getProgress()<100 && paragraph.status=='RUNNING'">
|
||||
<div id="{{paragraph.id}}_progress"
|
||||
class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width:{{getProgress()}}%;"></div>
|
||||
<span class="sr-only">{{getProgress()}}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="{{paragraph.id}}_form" role="form"
|
||||
ng-show="!paragraph.config.tableHide && !asIframe"
|
||||
class="form-horizontal">
|
||||
<div class="form-group"
|
||||
ng-repeat="formulaire in paragraph.settings.forms"
|
||||
ng-Init="loadForm(formulaire, paragraph.settings.params)">
|
||||
<label class="col-sm-1 control-label input-sm" ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }">{{formulaire.name}}</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control input-sm"
|
||||
ng-if="!paragraph.settings.forms[formulaire.name].options"
|
||||
ng-enter="runParagraph(getEditorValue())"
|
||||
ng-model="paragraph.settings.params[formulaire.name]"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }"
|
||||
name="{{formulaire.name}}">
|
||||
</input>
|
||||
|
||||
<select class="form-control input-sm"
|
||||
ng-if="paragraph.settings.forms[formulaire.name].options"
|
||||
ng-change="runParagraph(getEditorValue())"
|
||||
ng-model="paragraph.settings.params[formulaire.name]"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING' }"
|
||||
name="{{formulaire.name}}"
|
||||
ng-options="option.value as (option.displayName||option.value) for option in paragraph.settings.forms[formulaire.name].options"
|
||||
>
|
||||
<!--
|
||||
<option
|
||||
ng-repeat="option in paragraph.settings.forms[formulaire.name].options"
|
||||
value="{{option.value}}"
|
||||
>{{option.displayName || option.value}}
|
||||
</option>
|
||||
-->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Rendering -->
|
||||
<div class='tableDisplay' ng-show="!paragraph.config.tableHide">
|
||||
<div id="{{paragraph.id}}_switch"
|
||||
ng-if="paragraph.result.type == 'TABLE' && !asIframe && !viewOnly"
|
||||
class="btn-group"
|
||||
style='margin-bottom: 10px;'>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('table')}"
|
||||
ng-click="setGraphMode('table', true)" ><i class="fa fa-table"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('multiBarChart')}"
|
||||
ng-click="setGraphMode('multiBarChart', true)"><i class="fa fa-bar-chart"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('pieChart')}"
|
||||
ng-click="setGraphMode('pieChart', true)"><i class="fa fa-pie-chart"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('stackedAreaChart')}"
|
||||
ng-click="setGraphMode('stackedAreaChart', true)"><i class="fa fa-area-chart"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('lineChart')}"
|
||||
ng-click="setGraphMode('lineChart', true)"><i class="fa fa-line-chart"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm"
|
||||
ng-class="{'active': isGraphMode('scatterChart')}"
|
||||
ng-click="setGraphMode('scatterChart', true)"><i class="cf cf-scatter-chart"></i>
|
||||
</button>
|
||||
</div>
|
||||
<span ng-if="getResultType()=='TABLE' && getGraphMode()!='table' && !asIframe && !viewOnly"
|
||||
style="margin-left:10px; cursor:pointer; display: inline-block; vertical-align:top; position: relative; line-height:30px;">
|
||||
<a class="btnText" ng-if="paragraph.config.graph.optionOpen"
|
||||
ng-click="toggleGraphOption()">
|
||||
settings <span class="fa fa-caret-up"></span>
|
||||
</a>
|
||||
<a class="btnText" ng-if="!paragraph.config.graph.optionOpen"
|
||||
ng-click="toggleGraphOption()" >
|
||||
settings <span class="fa fa-caret-down"></span>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<div class="option lightBold" style="overflow: visible;"
|
||||
ng-if="getResultType()=='TABLE' && getGraphMode()!='table'
|
||||
&& paragraph.config.graph.optionOpen && !asIframe && !viewOnly">
|
||||
All fields:
|
||||
<div class="allFields row">
|
||||
<ul class="noDot">
|
||||
<li class="liVertical" ng-repeat="col in paragraph.result.columnNames">
|
||||
<div class="btn btn-default btn-xs"
|
||||
data-drag="true"
|
||||
data-jqyoui-options="{revert: 'invalid', helper: 'clone'}"
|
||||
ng-model="paragraph.result.columnNames"
|
||||
jqyoui-draggable="{index: {{$index}}, placeholder: 'keep'}">
|
||||
{{col.name | limitTo: 30}}{{col.name.length > 30 ? '...' : ''}}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="getGraphMode()!='scatterChart'">
|
||||
<div class="col-md-4">
|
||||
<span class="columns lightBold">
|
||||
Keys
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.keys"
|
||||
jqyoui-droppable="{multiple:true, onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled">
|
||||
<li ng-repeat="item in paragraph.config.graph.keys">
|
||||
<button class="btn btn-primary btn-xs">
|
||||
{{item.name}} <span class="fa fa-close" ng-click="removeGraphOptionKeys($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<span class="columns lightBold">
|
||||
Groups
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.groups"
|
||||
jqyoui-droppable="{multiple:true, onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled">
|
||||
<li ng-repeat="item in paragraph.config.graph.groups">
|
||||
<button class="btn btn-success btn-xs">
|
||||
{{item.name}} <span class="fa fa-close" ng-click="removeGraphOptionGroups($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<span class="columns lightBold">
|
||||
Values
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.values"
|
||||
jqyoui-droppable="{multiple:true, onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled">
|
||||
<li ng-repeat="item in paragraph.config.graph.values">
|
||||
<div class="btn-group">
|
||||
<div class="btn btn-info btn-xs dropdown-toggle"
|
||||
type="button"
|
||||
data-toggle="dropdown">
|
||||
{{item.name | limitTo: 30}}{{item.name.length > 30 ? '...' : ''}}
|
||||
<font style="color:#EEEEEE;"><span class="lightBold" style="text-transform: uppercase;">{{item.aggr}}</span></font>
|
||||
<span class="fa fa-close" ng-click="removeGraphOptionValues($index)"></span>
|
||||
</div>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li ng-click="setGraphOptionValueAggr($index, 'sum')"><a>sum</a></li>
|
||||
<li ng-click="setGraphOptionValueAggr($index, 'count')"><a>count</a></li>
|
||||
<li ng-click="setGraphOptionValueAggr($index, 'avg')"><a>avg</a></li>
|
||||
<li ng-click="setGraphOptionValueAggr($index, 'min')"><a>min</a></li>
|
||||
<li ng-click="setGraphOptionValueAggr($index, 'max')"><a>max</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="getGraphMode()=='scatterChart'">
|
||||
<div class="col-md-3">
|
||||
<span class="columns lightBold">
|
||||
xAxis
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.scatter.xAxis"
|
||||
jqyoui-droppable="{onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled"
|
||||
style="height:36px">
|
||||
<li ng-if="paragraph.config.graph.scatter.xAxis">
|
||||
<button class="btn btn-primary btn-xs">
|
||||
{{paragraph.config.graph.scatter.xAxis.name}} <span class="fa fa-close" ng-click="removeScatterOptionXaxis($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="columns lightBold">
|
||||
yAxis
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.scatter.yAxis"
|
||||
jqyoui-droppable="{onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled"
|
||||
style="height:36px">
|
||||
<li ng-if="paragraph.config.graph.scatter.yAxis">
|
||||
<button class="btn btn-success btn-xs">
|
||||
{{paragraph.config.graph.scatter.yAxis.name}} <span class="fa fa-close" ng-click="removeScatterOptionYaxis($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="columns lightBold">
|
||||
group
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.scatter.group"
|
||||
jqyoui-droppable="{onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled"
|
||||
style="height:36px">
|
||||
<li ng-if="paragraph.config.graph.scatter.group">
|
||||
<button class="btn btn-info btn-xs">
|
||||
{{paragraph.config.graph.scatter.group.name}} <span class="fa fa-close" ng-click="removeScatterOptionGroup($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="columns lightBold">
|
||||
size
|
||||
<a tabindex="0" class="fa fa-info-circle" role="button" popover-placement="top"
|
||||
popover-trigger="focus"
|
||||
popover-html-unsafe="<li>Size option is valid only when you drop numeric field here.</li>
|
||||
<li>When data in each axis are discrete, 'number of values in corresponding coordinate' will be used as size.</li>
|
||||
<li>Zeppelin consider values as discrete when the values contain string value or the number of distinct values are bigger than 5% of total number of values.</li>
|
||||
<li>Size field button turns to grey when the option you chose is not valid.</li>"></a>
|
||||
<ul data-drop="true"
|
||||
ng-model="paragraph.config.graph.scatter.size"
|
||||
jqyoui-droppable="{onDrop:'onGraphOptionChange()'}"
|
||||
class="list-unstyled"
|
||||
style="height:36px">
|
||||
<li ng-if="paragraph.config.graph.scatter.size">
|
||||
<button class="btn btn-xs" style="color:white" ng-class="{'btn-warning': isValidSizeOption(paragraph.config.graph.scatter, paragraph.result.rows)}">
|
||||
{{paragraph.config.graph.scatter.size.name}} <span class="fa fa-close" ng-click="removeScatterOptionSize($index)"></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="p{{paragraph.id}}_graph"
|
||||
class="graphContainer"
|
||||
ng-class="{'noOverflow': getGraphMode()=='table'}"
|
||||
ng-if="getResultType()=='TABLE'"
|
||||
allowresize="{{!asIframe && !viewOnly}}"
|
||||
resizable on-resize="setGraphHeight();">
|
||||
|
||||
<div ng-if="getGraphMode()=='table'"
|
||||
id="p{{paragraph.id}}_table"
|
||||
class="table">
|
||||
</div>
|
||||
|
||||
<div ng-if="getGraphMode()=='multiBarChart'"
|
||||
id="p{{paragraph.id}}_multiBarChart">
|
||||
<svg></svg>
|
||||
</div>
|
||||
|
||||
<div ng-if="getGraphMode()=='pieChart'"
|
||||
id="p{{paragraph.id}}_pieChart">
|
||||
<svg></svg>
|
||||
</div>
|
||||
|
||||
<div ng-if="getGraphMode()=='stackedAreaChart'"
|
||||
id="p{{paragraph.id}}_stackedAreaChart">
|
||||
<svg></svg>
|
||||
</div>
|
||||
|
||||
<div ng-if="getGraphMode()=='lineChart'"
|
||||
id="p{{paragraph.id}}_lineChart">
|
||||
<svg></svg>
|
||||
</div>
|
||||
|
||||
<div ng-if="getGraphMode()=='scatterChart'"
|
||||
id="p{{paragraph.id}}_scatterChart">
|
||||
<svg></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="{{paragraph.id}}_comment"
|
||||
class="text"
|
||||
ng-if="getResultType()=='TABLE' && paragraph.result.comment"
|
||||
ng-Init="loadResultType(paragraph.result)"
|
||||
ng-bind-html="paragraph.result.comment">
|
||||
</div>
|
||||
|
||||
<div id="{{paragraph.id}}_text"
|
||||
class="text"
|
||||
ng-if="paragraph.result.type == 'TEXT'"
|
||||
ng-Init="loadResultType(paragraph.result)"
|
||||
ng-bind="paragraph.result.msg">
|
||||
</div>
|
||||
|
||||
<div id="p{{paragraph.id}}_html"
|
||||
ng-if="paragraph.result.type == 'HTML'"
|
||||
ng-Init="loadResultType(paragraph.result)">
|
||||
</div>
|
||||
|
||||
<div id="p{{paragraph.id}}_angular"
|
||||
ng-if="paragraph.result.type == 'ANGULAR'"
|
||||
ng-Init="loadResultType(paragraph.result)">
|
||||
</div>
|
||||
|
||||
<img id="{{paragraph.id}}_img"
|
||||
ng-if="paragraph.result.type == 'IMG'"
|
||||
ng-Init="loadResultType(paragraph.result)"
|
||||
ng-src="{{getBase64ImageSrc(paragraph.result.msg)}}">
|
||||
</img>
|
||||
|
||||
<div id="{{paragraph.id}}_error"
|
||||
class="error"
|
||||
ng-if="paragraph.status == 'ERROR'"
|
||||
ng-bind="paragraph.errorMessage">
|
||||
</div>
|
||||
|
||||
<div id="{{paragraph.id}}_executionTime" class="executionTime" ng-bind-html="getExecutionTime()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="{{paragraph.id}}_control" class="control" ng-show="!asIframe">
|
||||
|
||||
<span>
|
||||
{{paragraph.status}}
|
||||
</span>
|
||||
|
||||
<span ng-if="paragraph.status=='RUNNING'">
|
||||
{{getProgress()}}%
|
||||
</span>
|
||||
|
||||
<!-- Run / Cancel button -->
|
||||
<span class="icon-control-play" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="Run this paragraph"
|
||||
ng-click="runParagraph(getEditorValue())"
|
||||
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING'"></span>
|
||||
<span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C" tooltip-placement="top" tooltip="Cancel"
|
||||
ng-click="cancelParagraph()"
|
||||
ng-show="paragraph.status=='RUNNING' || paragraph.status=='PENDING'"></span>
|
||||
|
||||
<span class="{{paragraph.config.editorHide ? 'icon-size-fullscreen' : 'icon-size-actual'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.editorHide ? 'Show' : 'Hide') + ' editor'}}"
|
||||
ng-click="toggleEditor()"></span>
|
||||
<span class="{{paragraph.config.tableHide ? 'icon-notebook' : 'icon-book-open'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.tableHide ? 'Show' : 'Hide') + ' output'}}"
|
||||
ng-click="toggleOutput()"></span>
|
||||
|
||||
<span class="dropdown navbar-right">
|
||||
<span class="icon-settings" style="cursor:pointer"
|
||||
data-toggle="dropdown"
|
||||
type="button">
|
||||
</span>
|
||||
<ul class="dropdown-menu" role="menu" style="width:200px;">
|
||||
<li>
|
||||
<a class="fa fa-arrows-h dropdown"> Width
|
||||
<form style="display:inline; margin-left:5px;">
|
||||
<select ng-model="paragraph.config.colWidth"
|
||||
class="selectpicker"
|
||||
ng-change="changeColWidth()"
|
||||
ng-options="col for col in colWidthOption"></select>
|
||||
</form>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-arrow-up" style="cursor:pointer"
|
||||
ng-click="moveUp()"> Move Up</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-arrow-down" style="cursor:pointer"
|
||||
ng-click="moveDown()"> Move Down</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-plus" style="cursor:pointer"
|
||||
ng-click="insertNew()"> Insert New</a>
|
||||
</li>
|
||||
<li>
|
||||
<!-- paragraph handler -->
|
||||
<a class="fa fa-font" style="cursor:pointer"
|
||||
ng-click="hideTitle()"
|
||||
ng-show="paragraph.config.title"> Hide title</a>
|
||||
<a class="fa fa-font" style="cursor:pointer"
|
||||
ng-click="showTitle()"
|
||||
ng-show="!paragraph.config.title"> Show title</a>
|
||||
</li>
|
||||
|
||||
<li><a class="icon-share-alt" style="cursor:pointer"
|
||||
ng-click="goToSingleParagraph()"> Link this paragraph</a>
|
||||
</li>
|
||||
<li>
|
||||
<!-- remove paragraph -->
|
||||
<a class="fa fa-times" style="cursor:pointer"
|
||||
ng-click="removeParagraph()"> Remove</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Reference in a new issue