Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 149 additions & 26 deletions zeppelin-web/src/app/jobmanager/jobmanager.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
});
};
});
58 changes: 54 additions & 4 deletions zeppelin-web/src/app/jobmanager/jobmanager.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,49 @@ <h3 class="new_h3">
</div>

<div class="row">
<div class="col-md-6 text-left">
<div class="form-inline">
<span class="labelBtn btn-group">
<button type="button"
class="btn btn-default btn-xs"
ng-click="onChangeRunJobToAlwaysTopToggle()"
ng-class="{true : 'btn-primary', false : ''}[filterConfig.isRunningAlwaysTop]"
tooltip-placement="right" tooltip="Running the Notebook always on top">
<i class="fa fa-thumb-tack"></i>
</button>
<button type="button"
class="btn btn-default btn-xs"
ng-click="onChangeSortAsc()"
tooltip-placement="right" tooltip="Sort by Notebook name">
<i class="fa" ng-class="{true: 'fa-sort-alpha-asc', false : 'fa-sort-alpha-desc'}[filterConfig.isSortByAsc]"></i>
</button>
</span>
<span class="labelBtn btn-group" style="margin-left: 0px;">
<button type="button" class="btn btn-default btn-xs dropdown-toggle"
data-toggle="dropdown"
style="width:100px; text-align: right !important;">
<span class="text-right">
{{filterValueToName(filterConfig.filterValueInterpreter)}}<span class="caret"></span>
</span>
</button>
<ul class="dropdown-menu pull-left" role="menu">
<li ng-repeat="interpreterOption in activeInterpreters">
<a style="cursor:pointer" ng-click="setFilterValue(interpreterOption.value)">
{{filterValueToName(interpreterOption.value)}}
</a>
</li>
</ul>
<input
class="job-note-name-query form-control btn-xs"
style="margin-left: 5px;"
placeholder="&#xf002 Filter"
type="text" ng-model="filterConfig.filterValueNotebookName"
ng-keyup="doFilterInputTyping($event, jobInfomations, filterConfig, isLoadingFilter)"/>
</span>
</div>
</div>
<div
class="col-md-12 text-right"
class="col-md-6 text-right"
style="padding-top: 6px;">
<span
ng-repeat="jobStatus in ['READY', 'FINISHED', 'ABORT', 'ERROR','PENDING','RUNNING']"
Expand Down Expand Up @@ -99,16 +140,25 @@ <h3 class="new_h3">
<div>
<div class="note-jump"></div>
<div
ng-if="jobInfomations.length > 0"
ng-repeat="notebookJob in jobInfomations"
ng-if="isLoadingFilter === true"
class="paragraph-col">
<div
class="job-space box job-margin text-center">
<i style="color: blue" class="fa fa-spinner spinAnimation">
</i>&nbsp;Loading...
</div>
</div>
<div
ng-if="JobInfomationsByFilter.length > 0"
ng-repeat="notebookJob in JobInfomationsByFilter"
class="paragraph-col">
<div ng-include src="'app/jobmanager/jobs/job.html'"
class="job-space box job-margin"
ng-controller="JobCtrl">
</div>
</div>
<div
ng-if="jobInfomations.length <= 0"
ng-if="isLoadingFilter === false && JobInfomationsByFilter.length <= 0"
class="paragraph-col">
<div
class="job-space box job-margin text-center">
Expand Down
16 changes: 14 additions & 2 deletions zeppelin-web/src/app/jobmanager/jobs/job-control.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@
</span>
<span>
<span ng-if="notebookJob.isRunningJob === true">
Notebook is RUNNING
RUNNING
</span>
<span ng-if="notebookJob.isRunningJob === false">
Notebook is READY
READY
</span>
</span>

<span ng-if="notebookJob.isRunningJob === true">
{{getProgress()}}%
</span>

<!-- Run / Cancel button -->
<span
ng-if="notebookJob.isRunningJob === false"
class="icon-control-play" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="START ALL Job"
ng-click="runNotebookJob(notebookJob.notebookId)">
</span>
<span
ng-if="notebookJob.isRunningJob === true"
class="icon-control-pause" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="STOP ALL Job"
ng-click="stopNotebookJob(notebookJob.notebookId)">
</span>
</div>
67 changes: 66 additions & 1 deletion zeppelin-web/src/app/jobmanager/jobs/job.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
});
});
}
}
});
};
});