http://git-wip-us.apache.org/repos/asf/flink/blob/4ea52d69/flink-runtime-web/web-dashboard/web/js/index.js ---------------------------------------------------------------------- diff --git a/flink-runtime-web/web-dashboard/web/js/index.js b/flink-runtime-web/web-dashboard/web/js/index.js index 776ef66..9c8f752 100644 --- a/flink-runtime-web/web-dashboard/web/js/index.js +++ b/flink-runtime-web/web-dashboard/web/js/index.js @@ -1,1775 +1,2 @@ -angular.module('flinkApp', ['ui.router', 'angularMoment']).run(["$rootScope", function($rootScope) { - $rootScope.sidebarVisible = false; - return $rootScope.showSidebar = function() { - $rootScope.sidebarVisible = !$rootScope.sidebarVisible; - return $rootScope.sidebarClass = 'force-show'; - }; -}]).value('flinkConfig', { - jobServer: '', - "refresh-interval": 10000 -}).run(["JobsService", "MainService", "flinkConfig", "$interval", function(JobsService, MainService, flinkConfig, $interval) { - return MainService.loadConfig().then(function(config) { - angular.extend(flinkConfig, config); - JobsService.listJobs(); - return $interval(function() { - return JobsService.listJobs(); - }, flinkConfig["refresh-interval"]); - }); -}]).config(["$uiViewScrollProvider", function($uiViewScrollProvider) { - return $uiViewScrollProvider.useAnchorScroll(); -}]).run(["$rootScope", "$state", function($rootScope, $state) { - return $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) { - if (toState.redirectTo) { - event.preventDefault(); - return $state.go(toState.redirectTo, toParams); - } - }); -}]).config(["$stateProvider", "$urlRouterProvider", function($stateProvider, $urlRouterProvider) { - $stateProvider.state("overview", { - url: "/overview", - views: { - main: { - templateUrl: "partials/overview.html", - controller: 'OverviewController' - } - } - }).state("running-jobs", { - url: "/running-jobs", - views: { - main: { - templateUrl: "partials/jobs/running-jobs.html", - controller: 'RunningJobsController' - } - } - }).state("completed-jobs", { - url: "/completed-jobs", - views: { - main: { - templateUrl: "partials/jobs/completed-jobs.html", - controller: 'CompletedJobsController' - } - } - }).state("single-job", { - url: "/jobs/{jobid}", - abstract: true, - views: { - main: { - templateUrl: "partials/jobs/job.html", - controller: 'SingleJobController' - } - } - }).state("single-job.plan", { - url: "", - redirectTo: "single-job.plan.subtasks", - views: { - details: { - templateUrl: "partials/jobs/job.plan.html", - controller: 'JobPlanController' - } - } - }).state("single-job.plan.subtasks", { - url: "", - views: { - 'node-details': { - templateUrl: "partials/jobs/job.plan.node-list.subtasks.html", - controller: 'JobPlanSubtasksController' - } - } - }).state("single-job.plan.taskmanagers", { - url: "/taskmanagers", - views: { - 'node-details': { - templateUrl: "partials/jobs/job.plan.node-list.taskmanagers.html", - controller: 'JobPlanTaskManagersController' - } - } - }).state("single-job.plan.accumulators", { - url: "/accumulators", - views: { - 'node-details': { - templateUrl: "partials/jobs/job.plan.node-list.accumulators.html", - controller: 'JobPlanAccumulatorsController' - } - } - }).state("single-job.plan.checkpoints", { - url: "/checkpoints", - views: { - 'node-details': { - templateUrl: "partials/jobs/job.plan.node-list.checkpoints.html", - controller: 'JobPlanCheckpointsController' - } - } - }).state("single-job.plan.backpressure", { - url: "/backpressure", - views: { - 'node-details': { - templateUrl: "partials/jobs/job.plan.node-list.backpressure.html", - controller: 'JobPlanBackPressureController' - } - } - }).state("single-job.timeline", { - url: "/timeline", - views: { - details: { - templateUrl: "partials/jobs/job.timeline.html" - } - } - }).state("single-job.timeline.vertex", { - url: "/{vertexId}", - views: { - vertex: { - templateUrl: "partials/jobs/job.timeline.vertex.html", - controller: 'JobTimelineVertexController' - } - } - }).state("single-job.exceptions", { - url: "/exceptions", - views: { - details: { - templateUrl: "partials/jobs/job.exceptions.html", - controller: 'JobExceptionsController' - } - } - }).state("single-job.properties", { - url: "/properties", - views: { - details: { - templateUrl: "partials/jobs/job.properties.html", - controller: 'JobPropertiesController' - } - } - }).state("single-job.config", { - url: "/config", - views: { - details: { - templateUrl: "partials/jobs/job.config.html" - } - } - }).state("all-manager", { - url: "/taskmanagers", - views: { - main: { - templateUrl: "partials/taskmanager/index.html", - controller: 'AllTaskManagersController' - } - } - }).state("single-manager", { - url: "/taskmanager/{taskmanagerid}", - views: { - main: { - templateUrl: "partials/taskmanager/taskmanager.html" - } - } - }).state("single-manager.metrics", { - url: "/metrics", - views: { - details: { - templateUrl: "partials/taskmanager/taskmanager.metrics.html", - controller: 'SingleTaskManagerController' - } - } - }).state("single-manager.stdout", { - url: "/stdout", - views: { - details: { - templateUrl: "partials/taskmanager/taskmanager.stdout.html", - controller: 'SingleTaskManagerStdoutController' - } - } - }).state("single-manager.log", { - url: "/log", - views: { - details: { - templateUrl: "partials/taskmanager/taskmanager.log.html", - controller: 'SingleTaskManagerLogsController' - } - } - }).state("jobmanager", { - url: "/jobmanager", - views: { - main: { - templateUrl: "partials/jobmanager/index.html" - } - } - }).state("jobmanager.config", { - url: "/config", - views: { - details: { - templateUrl: "partials/jobmanager/config.html", - controller: 'JobManagerConfigController' - } - } - }).state("jobmanager.stdout", { - url: "/stdout", - views: { - details: { - templateUrl: "partials/jobmanager/stdout.html", - controller: 'JobManagerStdoutController' - } - } - }).state("jobmanager.log", { - url: "/log", - views: { - details: { - templateUrl: "partials/jobmanager/log.html", - controller: 'JobManagerLogsController' - } - } - }).state("submit", { - url: "/submit", - views: { - main: { - templateUrl: "partials/submit.html", - controller: "JobSubmitController" - } - } - }); - return $urlRouterProvider.otherwise("/overview"); -}]); - -angular.module('flinkApp').directive('bsLabel', ["JobsService", function(JobsService) { - return { - transclude: true, - replace: true, - scope: { - getLabelClass: "&", - status: "@" - }, - template: "<span title='{{status}}' ng-class='getLabelClass()'><ng-transclude></ng-transclude></span>", - link: function(scope, element, attrs) { - return scope.getLabelClass = function() { - return 'label label-' + JobsService.translateLabelState(attrs.status); - }; - } - }; -}]).directive('bpLabel', ["JobsService", function(JobsService) { - return { - transclude: true, - replace: true, - scope: { - getBackPressureLabelClass: "&", - status: "@" - }, - template: "<span title='{{status}}' ng-class='getBackPressureLabelClass()'><ng-transclude></ng-transclude></span>", - link: function(scope, element, attrs) { - return scope.getBackPressureLabelClass = function() { - return 'label label-' + JobsService.translateBackPressureLabelState(attrs.status); - }; - } - }; -}]).directive('indicatorPrimary', ["JobsService", function(JobsService) { - return { - replace: true, - scope: { - getLabelClass: "&", - status: '@' - }, - template: "<i title='{{status}}' ng-class='getLabelClass()' />", - link: function(scope, element, attrs) { - return scope.getLabelClass = function() { - return 'fa fa-circle indicator indicator-' + JobsService.translateLabelState(attrs.status); - }; - } - }; -}]).directive('tableProperty', function() { - return { - replace: true, - scope: { - value: '=' - }, - template: "<td title=\"{{value || 'None'}}\">{{value || 'None'}}</td>" - }; -}); - -angular.module('flinkApp').filter("amDurationFormatExtended", ["angularMomentConfig", function(angularMomentConfig) { - var amDurationFormatExtendedFilter; - amDurationFormatExtendedFilter = function(value, format, durationFormat) { - if (typeof value === "undefined" || value === null) { - return ""; - } - return moment.duration(value, format).format(durationFormat, { - trim: false - }); - }; - amDurationFormatExtendedFilter.$stateful = angularMomentConfig.statefulFilters; - return amDurationFormatExtendedFilter; -}]).filter("humanizeDuration", function() { - return function(value, short) { - var days, hours, minutes, ms, seconds, x; - if (typeof value === "undefined" || value === null) { - return ""; - } - ms = value % 1000; - x = Math.floor(value / 1000); - seconds = x % 60; - x = Math.floor(x / 60); - minutes = x % 60; - x = Math.floor(x / 60); - hours = x % 24; - x = Math.floor(x / 24); - days = x; - if (days === 0) { - if (hours === 0) { - if (minutes === 0) { - if (seconds === 0) { - return ms + "ms"; - } else { - return seconds + "s "; - } - } else { - return minutes + "m " + seconds + "s"; - } - } else { - if (short) { - return hours + "h " + minutes + "m"; - } else { - return hours + "h " + minutes + "m " + seconds + "s"; - } - } - } else { - if (short) { - return days + "d " + hours + "h"; - } else { - return days + "d " + hours + "h " + minutes + "m " + seconds + "s"; - } - } - }; -}).filter("humanizeText", function() { - return function(text) { - if (text) { - return text.replace(/>/g, ">").replace(/<br\/>/g, ""); - } else { - return ''; - } - }; -}).filter("humanizeBytes", function() { - return function(bytes) { - var converter, units; - units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]; - converter = function(value, power) { - var base; - base = Math.pow(1024, power); - if (value < base) { - return (value / base).toFixed(2) + " " + units[power]; - } else if (value < base * 1000) { - return (value / base).toPrecision(3) + " " + units[power]; - } else { - return converter(value, power + 1); - } - }; - if (typeof bytes === "undefined" || bytes === null) { - return ""; - } - if (bytes < 1000) { - return bytes + " B"; - } else { - return converter(bytes, 1); - } - }; -}).filter("toUpperCase", function() { - return function(text) { - return text.toUpperCase(); - }; -}); - -angular.module('flinkApp').service('MainService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - this.loadConfig = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "config").success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]); - -angular.module('flinkApp').controller('JobManagerConfigController', ["$scope", "JobManagerConfigService", function($scope, JobManagerConfigService) { - return JobManagerConfigService.loadConfig().then(function(data) { - if ($scope.jobmanager == null) { - $scope.jobmanager = {}; - } - return $scope.jobmanager['config'] = data; - }); -}]).controller('JobManagerLogsController', ["$scope", "JobManagerLogsService", function($scope, JobManagerLogsService) { - JobManagerLogsService.loadLogs().then(function(data) { - if ($scope.jobmanager == null) { - $scope.jobmanager = {}; - } - return $scope.jobmanager['log'] = data; - }); - return $scope.reloadData = function() { - return JobManagerLogsService.loadLogs().then(function(data) { - return $scope.jobmanager['log'] = data; - }); - }; -}]).controller('JobManagerStdoutController', ["$scope", "JobManagerStdoutService", function($scope, JobManagerStdoutService) { - JobManagerStdoutService.loadStdout().then(function(data) { - if ($scope.jobmanager == null) { - $scope.jobmanager = {}; - } - return $scope.jobmanager['stdout'] = data; - }); - return $scope.reloadData = function() { - return JobManagerStdoutService.loadStdout().then(function(data) { - return $scope.jobmanager['stdout'] = data; - }); - }; -}]); - -angular.module('flinkApp').service('JobManagerConfigService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - var config; - config = {}; - this.loadConfig = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "jobmanager/config").success(function(data, status, headers, config) { - config = data; - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]).service('JobManagerLogsService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - var logs; - logs = {}; - this.loadLogs = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "jobmanager/log").success(function(data, status, headers, config) { - logs = data; - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]).service('JobManagerStdoutService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - var stdout; - stdout = {}; - this.loadStdout = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "jobmanager/stdout").success(function(data, status, headers, config) { - stdout = data; - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]); - -angular.module('flinkApp').controller('RunningJobsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { - $scope.jobObserver = function() { - return $scope.jobs = JobsService.getJobs('running'); - }; - JobsService.registerObserver($scope.jobObserver); - $scope.$on('$destroy', function() { - return JobsService.unRegisterObserver($scope.jobObserver); - }); - return $scope.jobObserver(); -}]).controller('CompletedJobsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { - $scope.jobObserver = function() { - return $scope.jobs = JobsService.getJobs('finished'); - }; - JobsService.registerObserver($scope.jobObserver); - $scope.$on('$destroy', function() { - return JobsService.unRegisterObserver($scope.jobObserver); - }); - return $scope.jobObserver(); -}]).controller('SingleJobController', ["$scope", "$state", "$stateParams", "JobsService", "$rootScope", "flinkConfig", "$interval", function($scope, $state, $stateParams, JobsService, $rootScope, flinkConfig, $interval) { - var refresher; - console.log('SingleJobController'); - $scope.jobid = $stateParams.jobid; - $scope.job = null; - $scope.plan = null; - $scope.vertices = null; - $scope.jobCheckpointStats = null; - $scope.showHistory = false; - $scope.backPressureOperatorStats = {}; - JobsService.loadJob($stateParams.jobid).then(function(data) { - $scope.job = data; - $scope.plan = data.plan; - return $scope.vertices = data.vertices; - }); - refresher = $interval(function() { - return JobsService.loadJob($stateParams.jobid).then(function(data) { - $scope.job = data; - return $scope.$broadcast('reload'); - }); - }, flinkConfig["refresh-interval"]); - $scope.$on('$destroy', function() { - $scope.job = null; - $scope.plan = null; - $scope.vertices = null; - $scope.jobCheckpointStats = null; - $scope.backPressureOperatorStats = null; - return $interval.cancel(refresher); - }); - $scope.cancelJob = function(cancelEvent) { - angular.element(cancelEvent.currentTarget).removeClass("btn").removeClass("btn-default").html('Cancelling...'); - return JobsService.cancelJob($stateParams.jobid).then(function(data) { - return {}; - }); - }; - $scope.stopJob = function(stopEvent) { - angular.element(stopEvent.currentTarget).removeClass("btn").removeClass("btn-default").html('Stopping...'); - return JobsService.stopJob($stateParams.jobid).then(function(data) { - return {}; - }); - }; - return $scope.toggleHistory = function() { - return $scope.showHistory = !$scope.showHistory; - }; -}]).controller('JobPlanController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { - console.log('JobPlanController'); - $scope.nodeid = null; - $scope.nodeUnfolded = false; - $scope.stateList = JobsService.stateList(); - $scope.changeNode = function(nodeid) { - if (nodeid !== $scope.nodeid) { - $scope.nodeid = nodeid; - $scope.vertex = null; - $scope.subtasks = null; - $scope.accumulators = null; - $scope.operatorCheckpointStats = null; - return $scope.$broadcast('reload'); - } else { - $scope.nodeid = null; - $scope.nodeUnfolded = false; - $scope.vertex = null; - $scope.subtasks = null; - $scope.accumulators = null; - return $scope.operatorCheckpointStats = null; - } - }; - $scope.deactivateNode = function() { - $scope.nodeid = null; - $scope.nodeUnfolded = false; - $scope.vertex = null; - $scope.subtasks = null; - $scope.accumulators = null; - return $scope.operatorCheckpointStats = null; - }; - return $scope.toggleFold = function() { - return $scope.nodeUnfolded = !$scope.nodeUnfolded; - }; -}]).controller('JobPlanSubtasksController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPlanSubtasksController'); - if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.st)) { - JobsService.getSubtasks($scope.nodeid).then(function(data) { - return $scope.subtasks = data; - }); - } - return $scope.$on('reload', function(event) { - console.log('JobPlanSubtasksController'); - if ($scope.nodeid) { - return JobsService.getSubtasks($scope.nodeid).then(function(data) { - return $scope.subtasks = data; - }); - } - }); -}]).controller('JobPlanTaskManagersController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPlanTaskManagersController'); - if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.st)) { - JobsService.getTaskManagers($scope.nodeid).then(function(data) { - return $scope.taskmanagers = data; - }); - } - return $scope.$on('reload', function(event) { - console.log('JobPlanTaskManagersController'); - if ($scope.nodeid) { - return JobsService.getTaskManagers($scope.nodeid).then(function(data) { - return $scope.taskmanagers = data; - }); - } - }); -}]).controller('JobPlanAccumulatorsController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPlanAccumulatorsController'); - if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.accumulators)) { - JobsService.getAccumulators($scope.nodeid).then(function(data) { - $scope.accumulators = data.main; - return $scope.subtaskAccumulators = data.subtasks; - }); - } - return $scope.$on('reload', function(event) { - console.log('JobPlanAccumulatorsController'); - if ($scope.nodeid) { - return JobsService.getAccumulators($scope.nodeid).then(function(data) { - $scope.accumulators = data.main; - return $scope.subtaskAccumulators = data.subtasks; - }); - } - }); -}]).controller('JobPlanCheckpointsController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPlanCheckpointsController'); - JobsService.getJobCheckpointStats($scope.jobid).then(function(data) { - return $scope.jobCheckpointStats = data; - }); - if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.operatorCheckpointStats)) { - JobsService.getOperatorCheckpointStats($scope.nodeid).then(function(data) { - $scope.operatorCheckpointStats = data.operatorStats; - return $scope.subtasksCheckpointStats = data.subtasksStats; - }); - } - return $scope.$on('reload', function(event) { - console.log('JobPlanCheckpointsController'); - JobsService.getJobCheckpointStats($scope.jobid).then(function(data) { - return $scope.jobCheckpointStats = data; - }); - if ($scope.nodeid) { - return JobsService.getOperatorCheckpointStats($scope.nodeid).then(function(data) { - $scope.operatorCheckpointStats = data.operatorStats; - return $scope.subtasksCheckpointStats = data.subtasksStats; - }); - } - }); -}]).controller('JobPlanBackPressureController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPlanBackPressureController'); - $scope.now = Date.now(); - if ($scope.nodeid) { - JobsService.getOperatorBackPressure($scope.nodeid).then(function(data) { - return $scope.backPressureOperatorStats[$scope.nodeid] = data; - }); - } - return $scope.$on('reload', function(event) { - console.log('JobPlanBackPressureController (relaod)'); - $scope.now = Date.now(); - if ($scope.nodeid) { - return JobsService.getOperatorBackPressure($scope.nodeid).then(function(data) { - return $scope.backPressureOperatorStats[$scope.nodeid] = data; - }); - } - }); -}]).controller('JobTimelineVertexController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { - console.log('JobTimelineVertexController'); - JobsService.getVertex($stateParams.vertexId).then(function(data) { - return $scope.vertex = data; - }); - return $scope.$on('reload', function(event) { - console.log('JobTimelineVertexController'); - return JobsService.getVertex($stateParams.vertexId).then(function(data) { - return $scope.vertex = data; - }); - }); -}]).controller('JobExceptionsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { - return JobsService.loadExceptions().then(function(data) { - return $scope.exceptions = data; - }); -}]).controller('JobPropertiesController', ["$scope", "JobsService", function($scope, JobsService) { - console.log('JobPropertiesController'); - return $scope.changeNode = function(nodeid) { - if (nodeid !== $scope.nodeid) { - $scope.nodeid = nodeid; - return JobsService.getNode(nodeid).then(function(data) { - return $scope.node = data; - }); - } else { - $scope.nodeid = null; - return $scope.node = null; - } - }; -}]); - -angular.module('flinkApp').directive('vertex', ["$state", function($state) { - return { - template: "<svg class='timeline secondary' width='0' height='0'></svg>", - scope: { - data: "=" - }, - link: function(scope, elem, attrs) { - var analyzeTime, containerW, svgEl; - svgEl = elem.children()[0]; - containerW = elem.width(); - angular.element(svgEl).attr('width', containerW); - analyzeTime = function(data) { - var chart, svg, testData; - d3.select(svgEl).selectAll("*").remove(); - testData = []; - angular.forEach(data.subtasks, function(subtask, i) { - var times; - times = [ - { - label: "Scheduled", - color: "#666", - borderColor: "#555", - starting_time: subtask.timestamps["SCHEDULED"], - ending_time: subtask.timestamps["DEPLOYING"], - type: 'regular' - }, { - label: "Deploying", - color: "#aaa", - borderColor: "#555", - starting_time: subtask.timestamps["DEPLOYING"], - ending_time: subtask.timestamps["RUNNING"], - type: 'regular' - } - ]; - if (subtask.timestamps["FINISHED"] > 0) { - times.push({ - label: "Running", - color: "#ddd", - borderColor: "#555", - starting_time: subtask.timestamps["RUNNING"], - ending_time: subtask.timestamps["FINISHED"], - type: 'regular' - }); - } - return testData.push({ - label: "(" + subtask.subtask + ") " + subtask.host, - times: times - }); - }); - chart = d3.timeline().stack().tickFormat({ - format: d3.time.format("%L"), - tickSize: 1 - }).prefix("single").labelFormat(function(label) { - return label; - }).margin({ - left: 100, - right: 0, - top: 0, - bottom: 0 - }).itemHeight(30).relativeTime(); - return svg = d3.select(svgEl).datum(testData).call(chart); - }; - analyzeTime(scope.data); - } - }; -}]).directive('timeline', ["$state", function($state) { - return { - template: "<svg class='timeline' width='0' height='0'></svg>", - scope: { - vertices: "=", - jobid: "=" - }, - link: function(scope, elem, attrs) { - var analyzeTime, containerW, svgEl, translateLabel; - svgEl = elem.children()[0]; - containerW = elem.width(); - angular.element(svgEl).attr('width', containerW); - translateLabel = function(label) { - return label.replace(">", ">"); - }; - analyzeTime = function(data) { - var chart, svg, testData; - d3.select(svgEl).selectAll("*").remove(); - testData = []; - angular.forEach(data, function(vertex) { - if (vertex['start-time'] > -1) { - if (vertex.type === 'scheduled') { - return testData.push({ - times: [ - { - label: translateLabel(vertex.name), - color: "#cccccc", - borderColor: "#555555", - starting_time: vertex['start-time'], - ending_time: vertex['end-time'], - type: vertex.type - } - ] - }); - } else { - return testData.push({ - times: [ - { - label: translateLabel(vertex.name), - color: "#d9f1f7", - borderColor: "#62cdea", - starting_time: vertex['start-time'], - ending_time: vertex['end-time'], - link: vertex.id, - type: vertex.type - } - ] - }); - } - } - }); - chart = d3.timeline().stack().click(function(d, i, datum) { - if (d.link) { - return $state.go("single-job.timeline.vertex", { - jobid: scope.jobid, - vertexId: d.link - }); - } - }).tickFormat({ - format: d3.time.format("%L"), - tickSize: 1 - }).prefix("main").margin({ - left: 0, - right: 0, - top: 0, - bottom: 0 - }).itemHeight(30).showBorderLine().showHourTimeline(); - return svg = d3.select(svgEl).datum(testData).call(chart); - }; - scope.$watch(attrs.vertices, function(data) { - if (data) { - return analyzeTime(data); - } - }); - } - }; -}]).directive('jobPlan', ["$timeout", function($timeout) { - return { - template: "<svg class='graph' width='500' height='400'><g /></svg> <svg class='tmp' width='1' height='1'><g /></svg> <div class='btn-group zoom-buttons'> <a class='btn btn-default zoom-in' ng-click='zoomIn()'><i class='fa fa-plus' /></a> <a class='btn btn-default zoom-out' ng-click='zoomOut()'><i class='fa fa-minus' /></a> </div>", - scope: { - plan: '=', - setNode: '&' - }, - link: function(scope, elem, attrs) { - var containerW, createEdge, createLabelEdge, createLabelNode, createNode, d3mainSvg, d3mainSvgG, d3tmpSvg, drawGraph, extendLabelNodeForIteration, g, getNodeType, isSpecialIterationNode, jobid, loadJsonToDagre, mainG, mainSvgElement, mainTmpElement, mainZoom, searchForNode, shortenString, subgraphs; - g = null; - mainZoom = d3.behavior.zoom(); - subgraphs = []; - jobid = attrs.jobid; - mainSvgElement = elem.children()[0]; - mainG = elem.children().children()[0]; - mainTmpElement = elem.children()[1]; - d3mainSvg = d3.select(mainSvgElement); - d3mainSvgG = d3.select(mainG); - d3tmpSvg = d3.select(mainTmpElement); - containerW = elem.width(); - angular.element(elem.children()[0]).width(containerW); - scope.zoomIn = function() { - var translate, v1, v2; - if (mainZoom.scale() < 2.99) { - translate = mainZoom.translate(); - v1 = translate[0] * (mainZoom.scale() + 0.1 / (mainZoom.scale())); - v2 = translate[1] * (mainZoom.scale() + 0.1 / (mainZoom.scale())); - mainZoom.scale(mainZoom.scale() + 0.1); - mainZoom.translate([v1, v2]); - return d3mainSvgG.attr("transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"); - } - }; - scope.zoomOut = function() { - var translate, v1, v2; - if (mainZoom.scale() > 0.31) { - mainZoom.scale(mainZoom.scale() - 0.1); - translate = mainZoom.translate(); - v1 = translate[0] * (mainZoom.scale() - 0.1 / (mainZoom.scale())); - v2 = translate[1] * (mainZoom.scale() - 0.1 / (mainZoom.scale())); - mainZoom.translate([v1, v2]); - return d3mainSvgG.attr("transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"); - } - }; - createLabelEdge = function(el) { - var labelValue; - labelValue = ""; - if ((el.ship_strategy != null) || (el.local_strategy != null)) { - labelValue += "<div class='edge-label'>"; - if (el.ship_strategy != null) { - labelValue += el.ship_strategy; - } - if (el.temp_mode !== undefined) { - labelValue += " (" + el.temp_mode + ")"; - } - if (el.local_strategy !== undefined) { - labelValue += ",<br>" + el.local_strategy; - } - labelValue += "</div>"; - } - return labelValue; - }; - isSpecialIterationNode = function(info) { - return info === "partialSolution" || info === "nextPartialSolution" || info === "workset" || info === "nextWorkset" || info === "solutionSet" || info === "solutionDelta"; - }; - getNodeType = function(el, info) { - if (info === "mirror") { - return 'node-mirror'; - } else if (isSpecialIterationNode(info)) { - return 'node-iteration'; - } else { - return 'node-normal'; - } - }; - createLabelNode = function(el, info, maxW, maxH) { - var labelValue, stepName; - labelValue = "<div href='#/jobs/" + jobid + "/vertex/" + el.id + "' class='node-label " + getNodeType(el, info) + "'>"; - if (info === "mirror") { - labelValue += "<h3 class='node-name'>Mirror of " + el.operator + "</h3>"; - } else { - labelValue += "<h3 class='node-name'>" + el.operator + "</h3>"; - } - if (el.description === "") { - labelValue += ""; - } else { - stepName = el.description; - stepName = shortenString(stepName); - labelValue += "<h4 class='step-name'>" + stepName + "</h4>"; - } - if (el.step_function != null) { - labelValue += extendLabelNodeForIteration(el.id, maxW, maxH); - } else { - if (isSpecialIterationNode(info)) { - labelValue += "<h5>" + info + " Node</h5>"; - } - if (el.parallelism !== "") { - labelValue += "<h5>Parallelism: " + el.parallelism + "</h5>"; - } - if (el.operator !== undefined) { - labelValue += "<h5>Operation: " + shortenString(el.operator_strategy) + "</h5>"; - } - } - labelValue += "</div>"; - return labelValue; - }; - extendLabelNodeForIteration = function(id, maxW, maxH) { - var labelValue, svgID; - svgID = "svg-" + id; - labelValue = "<svg class='" + svgID + "' width=" + maxW + " height=" + maxH + "><g /></svg>"; - return labelValue; - }; - shortenString = function(s) { - var sbr; - if (s.charAt(0) === "<") { - s = s.replace("<", "<"); - s = s.replace(">", ">"); - } - sbr = ""; - while (s.length > 30) { - sbr = sbr + s.substring(0, 30) + "<br>"; - s = s.substring(30, s.length); - } - sbr = sbr + s; - return sbr; - }; - createNode = function(g, data, el, isParent, maxW, maxH) { - if (isParent == null) { - isParent = false; - } - if (el.id === data.partial_solution) { - return g.setNode(el.id, { - label: createLabelNode(el, "partialSolution", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "partialSolution") - }); - } else if (el.id === data.next_partial_solution) { - return g.setNode(el.id, { - label: createLabelNode(el, "nextPartialSolution", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "nextPartialSolution") - }); - } else if (el.id === data.workset) { - return g.setNode(el.id, { - label: createLabelNode(el, "workset", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "workset") - }); - } else if (el.id === data.next_workset) { - return g.setNode(el.id, { - label: createLabelNode(el, "nextWorkset", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "nextWorkset") - }); - } else if (el.id === data.solution_set) { - return g.setNode(el.id, { - label: createLabelNode(el, "solutionSet", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "solutionSet") - }); - } else if (el.id === data.solution_delta) { - return g.setNode(el.id, { - label: createLabelNode(el, "solutionDelta", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "solutionDelta") - }); - } else { - return g.setNode(el.id, { - label: createLabelNode(el, "", maxW, maxH), - labelType: 'html', - "class": getNodeType(el, "") - }); - } - }; - createEdge = function(g, data, el, existingNodes, pred) { - var missingNode; - if (existingNodes.indexOf(pred.id) !== -1) { - return g.setEdge(pred.id, el.id, { - label: createLabelEdge(pred), - labelType: 'html', - arrowhead: 'normal' - }); - } else { - missingNode = searchForNode(data, pred.id); - if (!!missingNode) { - return g.setEdge(missingNode.id, el.id, { - label: createLabelEdge(missingNode), - labelType: 'html' - }); - } - } - }; - loadJsonToDagre = function(g, data) { - var el, existingNodes, isParent, k, l, len, len1, maxH, maxW, pred, r, ref, sg, toIterate; - existingNodes = []; - if (data.nodes != null) { - toIterate = data.nodes; - } else { - toIterate = data.step_function; - isParent = true; - } - for (k = 0, len = toIterate.length; k < len; k++) { - el = toIterate[k]; - maxW = 0; - maxH = 0; - if (el.step_function) { - sg = new dagreD3.graphlib.Graph({ - multigraph: true, - compound: true - }).setGraph({ - nodesep: 20, - edgesep: 0, - ranksep: 20, - rankdir: "LR", - marginx: 10, - marginy: 10 - }); - subgraphs[el.id] = sg; - loadJsonToDagre(sg, el); - r = new dagreD3.render(); - d3tmpSvg.select('g').call(r, sg); - maxW = sg.graph().width; - maxH = sg.graph().height; - angular.element(mainTmpElement).empty(); - } - createNode(g, data, el, isParent, maxW, maxH); - existingNodes.push(el.id); - if (el.inputs != null) { - ref = el.inputs; - for (l = 0, len1 = ref.length; l < len1; l++) { - pred = ref[l]; - createEdge(g, data, el, existingNodes, pred); - } - } - } - return g; - }; - searchForNode = function(data, nodeID) { - var el, i, j; - for (i in data.nodes) { - el = data.nodes[i]; - if (el.id === nodeID) { - return el; - } - if (el.step_function != null) { - for (j in el.step_function) { - if (el.step_function[j].id === nodeID) { - return el.step_function[j]; - } - } - } - } - }; - drawGraph = function(data) { - var i, newScale, renderer, sg, xCenterOffset, yCenterOffset; - g = new dagreD3.graphlib.Graph({ - multigraph: true, - compound: true - }).setGraph({ - nodesep: 70, - edgesep: 0, - ranksep: 50, - rankdir: "LR", - marginx: 40, - marginy: 40 - }); - loadJsonToDagre(g, data); - renderer = new dagreD3.render(); - d3mainSvgG.call(renderer, g); - for (i in subgraphs) { - sg = subgraphs[i]; - d3mainSvg.select('svg.svg-' + i + ' g').call(renderer, sg); - } - newScale = 0.5; - xCenterOffset = Math.floor((angular.element(mainSvgElement).width() - g.graph().width * newScale) / 2); - yCenterOffset = Math.floor((angular.element(mainSvgElement).height() - g.graph().height * newScale) / 2); - mainZoom.scale(newScale).translate([xCenterOffset, yCenterOffset]); - d3mainSvgG.attr("transform", "translate(" + xCenterOffset + ", " + yCenterOffset + ") scale(" + mainZoom.scale() + ")"); - mainZoom.on("zoom", function() { - var ev; - ev = d3.event; - return d3mainSvgG.attr("transform", "translate(" + ev.translate + ") scale(" + ev.scale + ")"); - }); - mainZoom(d3mainSvg); - return d3mainSvgG.selectAll('.node').on('click', function(d) { - return scope.setNode({ - nodeid: d - }); - }); - }; - scope.$watch(attrs.plan, function(newPlan) { - if (newPlan) { - return drawGraph(newPlan); - } - }); - } - }; -}]); - -angular.module('flinkApp').service('JobsService', ["$http", "flinkConfig", "$log", "amMoment", "$q", "$timeout", function($http, flinkConfig, $log, amMoment, $q, $timeout) { - var currentJob, currentPlan, deferreds, jobObservers, jobs, notifyObservers; - currentJob = null; - currentPlan = null; - deferreds = {}; - jobs = { - running: [], - finished: [], - cancelled: [], - failed: [] - }; - jobObservers = []; - notifyObservers = function() { - return angular.forEach(jobObservers, function(callback) { - return callback(); - }); - }; - this.registerObserver = function(callback) { - return jobObservers.push(callback); - }; - this.unRegisterObserver = function(callback) { - var index; - index = jobObservers.indexOf(callback); - return jobObservers.splice(index, 1); - }; - this.stateList = function() { - return ['SCHEDULED', 'DEPLOYING', 'RUNNING', 'FINISHED', 'FAILED', 'CANCELING', 'CANCELED']; - }; - this.translateLabelState = function(state) { - switch (state.toLowerCase()) { - case 'finished': - return 'success'; - case 'failed': - return 'danger'; - case 'scheduled': - return 'default'; - case 'deploying': - return 'info'; - case 'running': - return 'primary'; - case 'canceling': - return 'warning'; - case 'pending': - return 'info'; - case 'total': - return 'black'; - default: - return 'default'; - } - }; - this.setEndTimes = function(list) { - return angular.forEach(list, function(item, jobKey) { - if (!(item['end-time'] > -1)) { - return item['end-time'] = item['start-time'] + item['duration']; - } - }); - }; - this.processVertices = function(data) { - angular.forEach(data.vertices, function(vertex, i) { - return vertex.type = 'regular'; - }); - return data.vertices.unshift({ - name: 'Scheduled', - 'start-time': data.timestamps['CREATED'], - 'end-time': data.timestamps['CREATED'] + 1, - type: 'scheduled' - }); - }; - this.listJobs = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "joboverview").success((function(_this) { - return function(data, status, headers, config) { - angular.forEach(data, function(list, listKey) { - switch (listKey) { - case 'running': - return jobs.running = _this.setEndTimes(list); - case 'finished': - return jobs.finished = _this.setEndTimes(list); - case 'cancelled': - return jobs.cancelled = _this.setEndTimes(list); - case 'failed': - return jobs.failed = _this.setEndTimes(list); - } - }); - deferred.resolve(jobs); - return notifyObservers(); - }; - })(this)); - return deferred.promise; - }; - this.getJobs = function(type) { - return jobs[type]; - }; - this.getAllJobs = function() { - return jobs; - }; - this.loadJob = function(jobid) { - currentJob = null; - deferreds.job = $q.defer(); - $http.get(flinkConfig.jobServer + "jobs/" + jobid).success((function(_this) { - return function(data, status, headers, config) { - _this.setEndTimes(data.vertices); - _this.processVertices(data); - return $http.get(flinkConfig.jobServer + "jobs/" + jobid + "/config").success(function(jobConfig) { - data = angular.extend(data, jobConfig); - currentJob = data; - return deferreds.job.resolve(currentJob); - }); - }; - })(this)); - return deferreds.job.promise; - }; - this.getNode = function(nodeid) { - var deferred, seekNode; - seekNode = function(nodeid, data) { - var j, len, node, sub; - for (j = 0, len = data.length; j < len; j++) { - node = data[j]; - if (node.id === nodeid) { - return node; - } - if (node.step_function) { - sub = seekNode(nodeid, node.step_function); - } - if (sub) { - return sub; - } - } - return null; - }; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - var foundNode; - foundNode = seekNode(nodeid, currentJob.plan.nodes); - foundNode.vertex = _this.seekVertex(nodeid); - return deferred.resolve(foundNode); - }; - })(this)); - return deferred.promise; - }; - this.seekVertex = function(nodeid) { - var j, len, ref, vertex; - ref = currentJob.vertices; - for (j = 0, len = ref.length; j < len; j++) { - vertex = ref[j]; - if (vertex.id === nodeid) { - return vertex; - } - } - return null; - }; - this.getVertex = function(vertexid) { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - var vertex; - vertex = _this.seekVertex(vertexid); - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/subtasktimes").success(function(data) { - vertex.subtasks = data.subtasks; - return deferred.resolve(vertex); - }); - }; - })(this)); - return deferred.promise; - }; - this.getSubtasks = function(vertexid) { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid).success(function(data) { - var subtasks; - subtasks = data.subtasks; - return deferred.resolve(subtasks); - }); - }; - })(this)); - return deferred.promise; - }; - this.getTaskManagers = function(vertexid) { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/taskmanagers").success(function(data) { - var taskmanagers; - taskmanagers = data.taskmanagers; - return deferred.resolve(taskmanagers); - }); - }; - })(this)); - return deferred.promise; - }; - this.getAccumulators = function(vertexid) { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/accumulators").success(function(data) { - var accumulators; - accumulators = data['user-accumulators']; - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/subtasks/accumulators").success(function(data) { - var subtaskAccumulators; - subtaskAccumulators = data.subtasks; - return deferred.resolve({ - main: accumulators, - subtasks: subtaskAccumulators - }); - }); - }); - }; - })(this)); - return deferred.promise; - }; - this.getJobCheckpointStats = function(jobid) { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "jobs/" + jobid + "/checkpoints").success((function(_this) { - return function(data, status, headers, config) { - if (angular.equals({}, data)) { - return deferred.resolve(deferred.resolve(null)); - } else { - return deferred.resolve(data); - } - }; - })(this)); - return deferred.promise; - }; - this.getOperatorCheckpointStats = function(vertexid) { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/checkpoints").success(function(data) { - var operatorStats, subtaskStats; - if (angular.equals({}, data)) { - return deferred.resolve({ - operatorStats: null, - subtasksStats: null - }); - } else { - operatorStats = { - id: data['id'], - timestamp: data['timestamp'], - duration: data['duration'], - size: data['size'] - }; - if (angular.equals({}, data['subtasks'])) { - return deferred.resolve({ - operatorStats: operatorStats, - subtasksStats: null - }); - } else { - subtaskStats = data['subtasks']; - return deferred.resolve({ - operatorStats: operatorStats, - subtasksStats: subtaskStats - }); - } - } - }); - }; - })(this)); - return deferred.promise; - }; - this.getOperatorBackPressure = function(vertexid) { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/vertices/" + vertexid + "/backpressure").success((function(_this) { - return function(data) { - return deferred.resolve(data); - }; - })(this)); - return deferred.promise; - }; - this.translateBackPressureLabelState = function(state) { - switch (state.toLowerCase()) { - case 'in-progress': - return 'danger'; - case 'ok': - return 'success'; - case 'low': - return 'warning'; - case 'high': - return 'danger'; - default: - return 'default'; - } - }; - this.loadExceptions = function() { - var deferred; - deferred = $q.defer(); - deferreds.job.promise.then((function(_this) { - return function(data) { - return $http.get(flinkConfig.jobServer + "jobs/" + currentJob.jid + "/exceptions").success(function(exceptions) { - currentJob.exceptions = exceptions; - return deferred.resolve(exceptions); - }); - }; - })(this)); - return deferred.promise; - }; - this.cancelJob = function(jobid) { - return $http.get(flinkConfig.jobServer + "jobs/" + jobid + "/yarn-cancel"); - }; - this.stopJob = function(jobid) { - return $http.get("jobs/" + jobid + "/yarn-stop"); - }; - return this; -}]); - -angular.module('flinkApp').controller('OverviewController', ["$scope", "OverviewService", "JobsService", "$interval", "flinkConfig", function($scope, OverviewService, JobsService, $interval, flinkConfig) { - var refresh; - $scope.jobObserver = function() { - $scope.runningJobs = JobsService.getJobs('running'); - return $scope.finishedJobs = JobsService.getJobs('finished'); - }; - JobsService.registerObserver($scope.jobObserver); - $scope.$on('$destroy', function() { - return JobsService.unRegisterObserver($scope.jobObserver); - }); - $scope.jobObserver(); - OverviewService.loadOverview().then(function(data) { - return $scope.overview = data; - }); - refresh = $interval(function() { - return OverviewService.loadOverview().then(function(data) { - return $scope.overview = data; - }); - }, flinkConfig["refresh-interval"]); - return $scope.$on('$destroy', function() { - return $interval.cancel(refresh); - }); -}]); - -angular.module('flinkApp').service('OverviewService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - var overview; - overview = {}; - this.loadOverview = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "overview").success(function(data, status, headers, config) { - overview = data; - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]); - -angular.module('flinkApp').controller('JobSubmitController', ["$scope", "JobSubmitService", "$interval", "flinkConfig", "$state", "$location", function($scope, JobSubmitService, $interval, flinkConfig, $state, $location) { - var refresh; - $scope.yarn = $location.absUrl().indexOf("/proxy/application_") !== -1; - $scope.loadList = function() { - return JobSubmitService.loadJarList().then(function(data) { - $scope.address = data.address; - $scope.noaccess = data.error; - return $scope.jars = data.files; - }); - }; - $scope.defaultState = function() { - $scope.plan = null; - $scope.error = null; - return $scope.state = { - selected: null, - parallelism: "", - 'entry-class': "", - 'program-args': "", - 'plan-button': "Show Plan", - 'submit-button': "Submit", - 'action-time': 0 - }; - }; - $scope.defaultState(); - $scope.uploader = {}; - $scope.loadList(); - refresh = $interval(function() { - return $scope.loadList(); - }, flinkConfig["refresh-interval"]); - $scope.$on('$destroy', function() { - return $interval.cancel(refresh); - }); - $scope.selectJar = function(id) { - if ($scope.state.selected === id) { - return $scope.defaultState(); - } else { - $scope.defaultState(); - return $scope.state.selected = id; - } - }; - $scope.deleteJar = function(event, id) { - if ($scope.state.selected === id) { - $scope.defaultState(); - } - angular.element(event.currentTarget).removeClass("fa-remove").addClass("fa-spin fa-spinner"); - return JobSubmitService.deleteJar(id).then(function(data) { - angular.element(event.currentTarget).removeClass("fa-spin fa-spinner").addClass("fa-remove"); - if (data.error != null) { - return alert(data.error); - } - }); - }; - $scope.loadEntryClass = function(name) { - return $scope.state['entry-class'] = name; - }; - $scope.getPlan = function() { - var action; - if ($scope.state['plan-button'] === "Show Plan") { - action = new Date().getTime(); - $scope.state['action-time'] = action; - $scope.state['submit-button'] = "Submit"; - $scope.state['plan-button'] = "Getting Plan"; - $scope.error = null; - $scope.plan = null; - return JobSubmitService.getPlan($scope.state.selected, { - 'entry-class': $scope.state['entry-class'], - parallelism: $scope.state.parallelism, - 'program-args': $scope.state['program-args'] - }).then(function(data) { - if (action === $scope.state['action-time']) { - $scope.state['plan-button'] = "Show Plan"; - $scope.error = data.error; - return $scope.plan = data.plan; - } - }); - } - }; - $scope.runJob = function() { - var action; - if ($scope.state['submit-button'] === "Submit") { - action = new Date().getTime(); - $scope.state['action-time'] = action; - $scope.state['submit-button'] = "Submitting"; - $scope.state['plan-button'] = "Show Plan"; - $scope.error = null; - return JobSubmitService.runJob($scope.state.selected, { - 'entry-class': $scope.state['entry-class'], - parallelism: $scope.state.parallelism, - 'program-args': $scope.state['program-args'] - }).then(function(data) { - if (action === $scope.state['action-time']) { - $scope.state['submit-button'] = "Submit"; - $scope.error = data.error; - if (data.jobid != null) { - return $state.go("single-job.plan.subtasks", { - jobid: data.jobid - }); - } - } - }); - } - }; - $scope.nodeid = null; - $scope.changeNode = function(nodeid) { - if (nodeid !== $scope.nodeid) { - $scope.nodeid = nodeid; - $scope.vertex = null; - $scope.subtasks = null; - $scope.accumulators = null; - return $scope.$broadcast('reload'); - } else { - $scope.nodeid = null; - $scope.nodeUnfolded = false; - $scope.vertex = null; - $scope.subtasks = null; - return $scope.accumulators = null; - } - }; - $scope.clearFiles = function() { - return $scope.uploader = {}; - }; - $scope.uploadFiles = function(files) { - $scope.uploader = {}; - if (files.length === 1) { - $scope.uploader['file'] = files[0]; - return $scope.uploader['upload'] = true; - } else { - return $scope.uploader['error'] = "Did ya forget to select a file?"; - } - }; - return $scope.startUpload = function() { - var formdata, xhr; - if ($scope.uploader['file'] != null) { - formdata = new FormData(); - formdata.append("jarfile", $scope.uploader['file']); - $scope.uploader['upload'] = false; - $scope.uploader['success'] = "Initializing upload..."; - xhr = new XMLHttpRequest(); - xhr.upload.onprogress = function(event) { - $scope.uploader['success'] = null; - return $scope.uploader['progress'] = parseInt(100 * event.loaded / event.total); - }; - xhr.upload.onerror = function(event) { - $scope.uploader['progress'] = null; - return $scope.uploader['error'] = "An error occurred while uploading your file"; - }; - xhr.upload.onload = function(event) { - $scope.uploader['progress'] = null; - return $scope.uploader['success'] = "Saving..."; - }; - xhr.onreadystatechange = function() { - var response; - if (xhr.readyState === 4) { - response = JSON.parse(xhr.responseText); - if (response.error != null) { - $scope.uploader['error'] = response.error; - return $scope.uploader['success'] = null; - } else { - return $scope.uploader['success'] = "Uploaded!"; - } - } - }; - xhr.open("POST", "/jars/upload"); - return xhr.send(formdata); - } else { - return console.log("Unexpected Error. This should not happen"); - } - }; -}]).filter('getJarSelectClass', function() { - return function(selected, actual) { - if (selected === actual) { - return "fa-check-square"; - } else { - return "fa-square-o"; - } - }; -}); - -angular.module('flinkApp').service('JobSubmitService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - this.loadJarList = function() { - var deferred; - deferred = $q.defer(); - $http.get("jars/").success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - this.deleteJar = function(id) { - var deferred; - deferred = $q.defer(); - $http["delete"]("jars/" + id).success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - this.getPlan = function(id, args) { - var deferred; - deferred = $q.defer(); - $http.get("jars/" + id + "/plan", { - params: args - }).success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - this.runJob = function(id, args) { - var deferred; - deferred = $q.defer(); - $http.post("jars/" + id + "/run", {}, { - params: args - }).success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]); - -angular.module('flinkApp').controller('AllTaskManagersController', ["$scope", "TaskManagersService", "$interval", "flinkConfig", function($scope, TaskManagersService, $interval, flinkConfig) { - var refresh; - TaskManagersService.loadManagers().then(function(data) { - return $scope.managers = data; - }); - refresh = $interval(function() { - return TaskManagersService.loadManagers().then(function(data) { - return $scope.managers = data; - }); - }, flinkConfig["refresh-interval"]); - return $scope.$on('$destroy', function() { - return $interval.cancel(refresh); - }); -}]).controller('SingleTaskManagerController', ["$scope", "$stateParams", "SingleTaskManagerService", "$interval", "flinkConfig", function($scope, $stateParams, SingleTaskManagerService, $interval, flinkConfig) { - var refresh; - $scope.metrics = {}; - SingleTaskManagerService.loadMetrics($stateParams.taskmanagerid).then(function(data) { - return $scope.metrics = data[0]; - }); - refresh = $interval(function() { - return SingleTaskManagerService.loadMetrics($stateParams.taskmanagerid).then(function(data) { - return $scope.metrics = data[0]; - }); - }, flinkConfig["refresh-interval"]); - return $scope.$on('$destroy', function() { - return $interval.cancel(refresh); - }); -}]).controller('SingleTaskManagerLogsController', ["$scope", "$stateParams", "SingleTaskManagerService", "$interval", "flinkConfig", function($scope, $stateParams, SingleTaskManagerService, $interval, flinkConfig) { - $scope.log = {}; - SingleTaskManagerService.loadLogs($stateParams.taskmanagerid).then(function(data) { - return $scope.log = data; - }); - $scope.reloadData = function() { - return SingleTaskManagerService.loadLogs($stateParams.taskmanagerid).then(function(data) { - return $scope.log = data; - }); - }; - return $scope.downloadData = function() { - return window.location.href = "/taskmanagers/" + $stateParams.taskmanagerid + "/log"; - }; -}]).controller('SingleTaskManagerStdoutController', ["$scope", "$stateParams", "SingleTaskManagerService", "$interval", "flinkConfig", function($scope, $stateParams, SingleTaskManagerService, $interval, flinkConfig) { - $scope.stdout = {}; - SingleTaskManagerService.loadStdout($stateParams.taskmanagerid).then(function(data) { - return $scope.stdout = data; - }); - $scope.reloadData = function() { - return SingleTaskManagerService.loadStdout($stateParams.taskmanagerid).then(function(data) { - return $scope.stdout = data; - }); - }; - return $scope.downloadData = function() { - return window.location.href = "/taskmanagers/" + $stateParams.taskmanagerid + "/stdout"; - }; -}]); - -angular.module('flinkApp').service('TaskManagersService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - this.loadManagers = function() { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "taskmanagers").success(function(data, status, headers, config) { - return deferred.resolve(data['taskmanagers']); - }); - return deferred.promise; - }; - return this; -}]).service('SingleTaskManagerService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { - this.loadMetrics = function(taskmanagerid) { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "taskmanagers/" + taskmanagerid + "/metrics").success(function(data, status, headers, config) { - return deferred.resolve(data['taskmanagers']); - }); - return deferred.promise; - }; - this.loadLogs = function(taskmanagerid) { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "taskmanagers/" + taskmanagerid + "/log").success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - this.loadStdout = function(taskmanagerid) { - var deferred; - deferred = $q.defer(); - $http.get(flinkConfig.jobServer + "taskmanagers/" + taskmanagerid + "/stdout").success(function(data, status, headers, config) { - return deferred.resolve(data); - }); - return deferred.promise; - }; - return this; -}]); - -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmNvZmZlZSIsImluZGV4LmpzIiwiY29tbW9uL2RpcmVjdGl2ZXMuY29mZmVlIiwiY29tbW9uL2RpcmVjdGl2ZXMuanMiLCJjb21tb24vZmlsdGVycy5jb2ZmZWUiLCJjb21tb24vZmlsdGVycy5qcyIsImNvbW1vbi9zZXJ2aWNlcy5jb2ZmZWUiLCJjb21tb24vc2VydmljZXMuanMiLCJtb2R1bGVzL2pvYm1hbmFnZXIvam9ibWFuYWdlci5jdHJsLmNvZmZlZSIsIm1vZHVsZXMvam9ibWFuYWdlci9qb2JtYW5hZ2VyLmN0cmwuanMiLCJtb2R1bGVzL2pvYm1hbmFnZXIvam9ibWFuYWdlci5zdmMuY29mZmVlIiwibW9kdWxlcy9qb2JtYW5hZ2VyL2pvYm1hbmFnZXIuc3ZjLmpzIiwibW9kdWxlcy9qb2JzL2pvYnMuY3RybC5jb2ZmZWUiLCJtb2R1bGVzL2pvYnMvam9icy5jdHJsLmpzIiwibW9kdWxlcy9qb2JzL2pvYnMuZGlyLmNvZmZlZSIsIm1vZHVsZXMvam9icy9qb2JzLmRpci5qcyIsIm1vZHVsZXMvam9icy9qb2JzLnN2Yy5jb2ZmZWUiLCJtb2R1bGVzL2pvYnMvam9icy5zdmMuanMiLCJtb2R1bGVzL292ZXJ2aWV3L292ZXJ2aWV3LmN0cmwuY29mZmVlIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5jdHJsLmpzIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5zdmMuY29mZmVlIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5zdmMuanMiLCJtb2R1bGVzL3N1Ym1pdC9zdW JtaXQuY3RybC5jb2ZmZWUiLCJtb2R1bGVzL3N1Ym1pdC9zdWJtaXQuY3RybC5qcyIsIm1vZHVsZXMvc3VibWl0L3N1Ym1pdC5zdmMuY29mZmVlIiwibW9kdWxlcy9zdWJtaXQvc3VibWl0LnN2Yy5qcyIsIm1vZHVsZXMvdGFza21hbmFnZXIvdGFza21hbmFnZXIuY3RybC5jb2ZmZWUiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5hZ2VyLmN0cmwuanMiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5hZ2VyLnN2Yy5jb2ZmZWUiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5hZ2VyLnN2Yy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkEsUUFBUSxPQUFPLFlBQVksQ0FBQyxhQUFhLGtCQUl4QyxtQkFBSSxTQUFDLFlBQUQ7RUFDSCxXQUFXLGlCQUFpQjtFQ3JCNUIsT0RzQkEsV0FBVyxjQUFjLFdBQUE7SUFDdkIsV0FBVyxpQkFBaUIsQ0FBQyxXQUFXO0lDckJ4QyxPRHNCQSxXQUFXLGVBQWU7O0lBSTdCLE1BQU0sZUFBZTtFQUNwQixXQUFXO0VBRVgsb0JBQW9CO0dBS3JCLCtEQUFJLFNBQUMsYUFBYSxhQUFhLGFBQWEsV0FBeEM7RUM1QkgsT0Q2QkEsWUFBWSxhQUFhLEtBQUssU0FBQyxRQUFEO0lBQzVCLFFBQVEsT0FBTyxhQUFhO0lBRTVCLFlBQVk7SUM3QlosT0QrQkEsVUFBVSxXQUFBO01DOUJSLE9EK0JBLFlBQVk7T0FDWixZQUFZOztJQUtqQixpQ0FBTyxTQUFDLHVCQUFEO0VDakNOLE9Ea0NBLHNCQUFzQjtJQUl2Qiw2QkFBSSxTQUFDLFlBQVksUUFBYjtFQ3BDSCxPRHFDQSxXQUFXLEl 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
<TRUNCATED>
