diff --git a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js index 81696b560cd..7dc7ce30ff2 100644 --- a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js +++ b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js @@ -14,44 +14,78 @@ 'use strict'; angular.module('zeppelinWebApp') - .controller('JobmanagerCtrl', - function($scope, websocketMsgSrv, $interval) { + .filter('jobManager', function() { - $scope.filterValueToName = function(filterValue) { - var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: filterValue}); + function filterContext(jobItems, filterConfig) { + var filterValueInterpreter = filterConfig.filterValueInterpreter; + var filterValueNotebookName = filterConfig.filterValueNotebookName; + var isRunningAlwaysTop = filterConfig.isRunningAlwaysTop; + var isSortByAsc = filterConfig.isSortByAsc; - if ($scope.ACTIVE_INTERPRETERS[index].name !== undefined) { - return $scope.ACTIVE_INTERPRETERS[index].name; - } else { - return 'undefined'; - } - }; + var filterItems = jobItems; - $scope.init = function() { - $scope.jobInfomations = []; - $scope.JobInfomationsByFilter = $scope.jobInfomations; + if (filterValueInterpreter === undefined) { + filterItems = _.filter(filterItems, function(jobItem) { + return jobItem.interpreter === undefined ? true : false; + }); + } else if (filterValueInterpreter !== '*') { + filterItems = _.where(filterItems, {interpreter: filterValueInterpreter}); + } - websocketMsgSrv.getNotebookJobsList(); - var refreshObj = $interval(function() { - if ($scope.lastJobServerUnixTime !== undefined) { - websocketMsgSrv.getUpdateNotebookJobsList($scope.lastJobServerUnixTime); - } - }, 1000); + if (filterValueNotebookName !== '') { + filterItems = _.filter(filterItems, function(jobItem) { + var lowerFilterValue = filterValueNotebookName.toLocaleLowerCase(); + var lowerNotebookName = jobItem.notebookName.toLocaleLowerCase(); + return lowerNotebookName.match(new RegExp('.*' + lowerFilterValue + '.*')); + }); + } - $scope.$on('$destroy', function() { - $interval.cancel(refreshObj); - websocketMsgSrv.unsubscribeJobManager(); + if (isSortByAsc === true) { + filterItems = _.sortBy(filterItems, function(sortItem) { + return sortItem.notebookName; }); - }; + } else { + filterItems = _.sortBy(filterItems, function(sortItem) { + return sortItem.notebookName; + }); + filterItems = filterItems.reverse(); + } - /* - ** $scope.$on functions below - */ + if (isRunningAlwaysTop === true) { + var runningJobList = _.where(filterItems, {isRunningJob: true}); + filterItems = _.reject(filterItems, {isRunningJob: true}); + runningJobList.map(function(runningJob) { + filterItems.splice(0,0, runningJob); + }); + } + + return filterItems; + } + return filterContext; + }) + .controller('JobmanagerCtrl', + function($scope, $route, $routeParams, $location, $rootScope, $http, $q, + websocketMsgSrv, baseUrlSrv, $interval, $timeout, jobManagerFilter) { $scope.$on('setNotebookJobs', function(event, responseData) { $scope.lastJobServerUnixTime = responseData.lastResponseUnixTime; $scope.jobInfomations = responseData.jobs; $scope.jobInfomationsIndexs = $scope.jobInfomations ? _.indexBy($scope.jobInfomations, 'notebookId') : {}; + $scope.JobInfomationsByFilter = $scope.jobTypeFilter($scope.jobInfomations, $scope.filterConfig); + $scope.activeInterpreters = [ + { + name: 'ALL', + value: '*' + } + ]; + var interpreterLists = _.uniq(_.pluck($scope.jobInfomations, 'interpreter'), false); + for (var index = 0, length = interpreterLists.length; index < length; index++) { + $scope.activeInterpreters.push({ + name: interpreterLists[index], + value: interpreterLists[index] + }); + } + $scope.doFiltering($scope.jobInfomations, $scope.filterConfig); }); $scope.$on('setUpdateNotebookJobs', function(event, responseData) { @@ -90,6 +124,95 @@ angular.module('zeppelinWebApp') changeOriginTarget.paragraphs = changedItem.paragraphs; } } + $scope.doFiltering(jobInfomations, $scope.filterConfig); }); }); + + $scope.doFiltering = function(jobInfomations, filterConfig) { + asyncNotebookJobFilter(jobInfomations, filterConfig).then( + function() { + // success + $scope.isLoadingFilter = false; + }, + function() { + // failed + }); + }; + + $scope.filterValueToName = function(filterValue, maxStringLength) { + if ($scope.activeInterpreters === undefined) { + return; + } + var index = _.findIndex($scope.activeInterpreters, {value: filterValue}); + if (index < 0) { + console.log('filtervalue [{}]', filterValue, ' ', $scope.activeInterpreters); + } + if ($scope.activeInterpreters[index].name !== undefined) { + if (maxStringLength !== undefined && maxStringLength > $scope.activeInterpreters[index].name) { + return $scope.activeInterpreters[index].name.substr(0, maxStringLength - 3) + '...'; + } + return $scope.activeInterpreters[index].name; + } else { + return 'Undefined'; + } + }; + + $scope.setFilterValue = function(filterValue) { + $scope.filterConfig.filterValueInterpreter = filterValue; + $scope.doFiltering($scope.jobInfomations, $scope.filterConfig); + }; + + $scope.onChangeRunJobToAlwaysTopToggle = function() { + $scope.filterConfig.isRunningAlwaysTop = !$scope.filterConfig.isRunningAlwaysTop; + $scope.doFiltering($scope.jobInfomations, $scope.filterConfig); + }; + + $scope.onChangeSortAsc = function() { + $scope.filterConfig.isSortByAsc = !$scope.filterConfig.isSortByAsc; + $scope.doFiltering($scope.jobInfomations, $scope.filterConfig); + }; + + $scope.doFilterInputTyping = function(keyEvent, jobInfomations, filterConfig) { + var RETURN_KEY_CODE = 13; + $timeout.cancel($scope.dofilterTimeoutObject); + $scope.dofilterTimeoutObject = $timeout(function() { + $scope.doFiltering(jobInfomations, filterConfig); + }, 1000); + if (keyEvent.which === RETURN_KEY_CODE) { + $timeout.cancel($scope.dofilterTimeoutObject); + $scope.doFiltering(jobInfomations, filterConfig); + } + }; + + $scope.init = function() { + $scope.isLoadingFilter = true; + $scope.filterConfig = { + isRunningAlwaysTop: true, + filterValueNotebookName: '', + filterValueInterpreter: '*', + isSortByAsc: true + }; + $scope.jobTypeFilter = jobManagerFilter; + $scope.jobInfomations = []; + $scope.JobInfomationsByFilter = $scope.jobInfomations; + + websocketMsgSrv.getNotebookJobsList(); + var refreshObj = $interval(function() { + if ($scope.lastJobServerUnixTime !== undefined) { + websocketMsgSrv.getUpdateNotebookJobsList($scope.lastJobServerUnixTime); + } + }, 1000); + + $scope.$on('$destroy', function() { + $interval.cancel(refreshObj); + websocketMsgSrv.unsubscribeJobManager(); + }); + }; + + var asyncNotebookJobFilter = function(jobInfomations, filterConfig) { + return $q(function(resolve, reject) { + $scope.JobInfomationsByFilter = $scope.jobTypeFilter(jobInfomations, filterConfig); + resolve($scope.JobInfomationsByFilter); + }); + }; }); diff --git a/zeppelin-web/src/app/jobmanager/jobmanager.html b/zeppelin-web/src/app/jobmanager/jobmanager.html index 598c3f7c006..63954e48af2 100644 --- a/zeppelin-web/src/app/jobmanager/jobmanager.html +++ b/zeppelin-web/src/app/jobmanager/jobmanager.html @@ -32,8 +32,49 @@

+
+
+ + + + + + + + + +
+
+
+ +  Loading... +
+
+
diff --git a/zeppelin-web/src/app/jobmanager/jobs/job-control.html b/zeppelin-web/src/app/jobmanager/jobs/job-control.html index 2cd0bf8e05b..f8d56df428d 100644 --- a/zeppelin-web/src/app/jobmanager/jobs/job-control.html +++ b/zeppelin-web/src/app/jobmanager/jobs/job-control.html @@ -18,14 +18,26 @@ - Notebook is RUNNING + RUNNING - Notebook is READY + READY {{getProgress()}}% + + + + + +
diff --git a/zeppelin-web/src/app/jobmanager/jobs/job.controller.js b/zeppelin-web/src/app/jobmanager/jobs/job.controller.js index cbbf986cdd7..22066333156 100644 --- a/zeppelin-web/src/app/jobmanager/jobs/job.controller.js +++ b/zeppelin-web/src/app/jobmanager/jobs/job.controller.js @@ -14,7 +14,7 @@ 'use strict'; angular.module('zeppelinWebApp') - .controller('JobCtrl', function($scope) { + .controller('JobCtrl', function($scope, $http, baseUrlSrv) { $scope.init = function(jobInformation) { $scope.progressValue = 0; @@ -35,4 +35,69 @@ angular.module('zeppelinWebApp') return isNaN(result) ? 0 : result; }; + $scope.lastExecuteTime = function(unixtime) { + return moment.unix(unixtime / 1000).fromNow(); + }; + + $scope.runNotebookJob = function(notebookId) { + BootstrapDialog.confirm({ + closable: true, + title: '', + message: 'Run all paragraphs?', + callback: function(result) { + if (result === true) { + $http({ + method: 'POST', + url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).then(function successCallback(response) { + // success + }, function errorCallback(errorResponse) { + var errorText = 'SERVER ERROR'; + if (errorResponse.data.message !== undefined) { + errorText = errorResponse.data.message; + } + BootstrapDialog.alert({ + closable: true, + title: 'Execution Failure', + message: errorText + }); + }); + } + } + }); + }; + + $scope.stopNotebookJob = function(notebookId) { + BootstrapDialog.confirm({ + closable: true, + title: '', + message: 'Stop all paragraphs?', + callback: function(result) { + if (result === true) { + $http({ + method: 'DELETE', + url: baseUrlSrv.getRestApiBase() + '/notebook/job/' + notebookId, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).then(function successCallback(response) { + // success + }, function errorCallback(errorResponse) { + var errorText = 'SERVER ERROR'; + if (errorResponse.data.message !== undefined) { + errorText = errorResponse.data.message; + } + BootstrapDialog.alert({ + closable: true, + title: 'Stop Failure', + message: errorText + }); + }); + } + } + }); + }; });