azkaban-developers
Changes
src/web/css/azkaban.css 73(+72 -1)
src/web/js/azkaban.date.utils.js 4(+2 -2)
src/web/js/azkaban.exflow.view.js 165(+150 -15)
Details
diff --git a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
index 676affe..150cfeb 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
@@ -42,8 +42,8 @@
#end
<div id="all-jobs-content">
- <div class="section-hd">
- <h2><a href="${context}/executor?execid=${execid}">Execution <span>$execid</span></a></h2>
+ <div class="section-hd flow-header">
+ <h2><a href="${context}/executor?execid=${execid}">Flow Execution <span>$execid</span></a></h2>
<div class="section-sub-hd">
<h4><a href="${context}/manager?project=${projectName}">Project <span>$projectName</span></a></h4>
<h4 class="separator">></h4>
@@ -75,7 +75,21 @@
</div>
</div>
<div id="jobListView">
- <p>This is my joblist view</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th class="timeline">Timeline</th>
+ <th class="date">Start Time</th>
+ <th class="date">End Time</th>
+ <th class="elapse">Elapsed</th>
+ <th class="status">Status</th>
+ <th class="logs">Logs</th>
+ </tr>
+ </thead>
+ <tbody id="executableBody">
+ </tbody>
+ </table>
</div>
</div>
#end
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index f7ede12..f0853ff 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -40,7 +40,7 @@
#end
<div id="all-jobs-content">
- <div class="section-hd">
+ <div class="section-hd flow-header">
<h2><a href="${context}/manager?project=${project.name}&flow=${flowid}">Flow <span>$flowid</span></a></h2>
<div class="section-sub-hd">
<h4><a href="${context}/manager?project=${project.name}">Project <span>$project.name</span></a></h4>
src/web/css/azkaban.css 73(+72 -1)
diff --git a/src/web/css/azkaban.css b/src/web/css/azkaban.css
index d57c62e..65437f9 100644
--- a/src/web/css/azkaban.css
+++ b/src/web/css/azkaban.css
@@ -1415,7 +1415,7 @@ span.sublabel {
}
#flow-status table td.SUCCEEDED {
- color: #00CC33;
+ color: #4e911e;
}
#flow-status table td.RUNNING {
@@ -1438,6 +1438,77 @@ span.sublabel {
font-weight: bold;
}
+#jobListView table th.date {
+ width: 140px;
+}
+
+#jobListView table th.elapse {
+ width: 90px;
+}
+
+#jobListView table th.status {
+ width: 100px;
+}
+
+#jobListView table th.logs {
+ width: 10px;
+}
+
+#jobListView table th.timeline {
+ width: 280px;
+}
+
+#jobListView table td.timeline {
+ padding: 0px;
+ height: 100%;
+ vertical-align: bottom;
+ margin: 0px;
+}
+
+#jobListView table td {
+ padding-left: 6px;
+ height: 20px;
+}
+
+.flow-header {
+ height: 48px;
+}
+
+.outerProgress {
+ width: 280px;
+ margin: 4px;
+ background-color: #e2e4e3;
+}
+
+.progressBox {
+ height: 24px;
+ background-color: #CCC;
+}
+
+.progressBox.SUCCEEDED {
+ background-color: #4e911e;
+ background: -moz-linear-gradient(top, #5bb41c 0, #598d1e 100%);
+ background: -o-linear-gradient(top, #5bb41c 0, #598d1e 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0,#5bb41c), color-stop(100%,#598d1e));
+ background: linear-gradient(top, #5bb41c 0, #598d1e 100%);
+}
+
+.progressBox.FAILED {
+ background-color: #9e3600;
+ background: -moz-linear-gradient(top, #d43c00 0, #9e3600 100%);
+ background: -o-linear-gradient(top, #d43c00 0, #9e3600 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0,#d43c00), color-stop(100%,#9e3600));
+ background: linear-gradient(top, #d43c00 0, #9e3600 100%);
+}
+
+.progressBox.RUNNING {
+ background-color: #009FC9;
+ background: -moz-linear-gradient(top, #009FC9 0, #007b9b 100%);
+ background: -o-linear-gradient(top, #009FC9 0, #007b9b 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0,#009FC9), color-stop(100%,#007b9b));
+ background: linear-gradient(top, #009FC9 0, #007b9b 100%);
+}
+
/* old styles */
.azkaban-charts .hitarea {
src/web/js/azkaban.date.utils.js 4(+2 -2)
diff --git a/src/web/js/azkaban.date.utils.js b/src/web/js/azkaban.date.utils.js
index 2f6f01e..056542d 100644
--- a/src/web/js/azkaban.date.utils.js
+++ b/src/web/js/azkaban.date.utils.js
@@ -25,13 +25,13 @@ var getDuration = function(startMs, endMs) {
var hours = Math.floor(mins / 60);
mins = mins % 60;
if (hours < 24) {
- return hours + "h " + mins + " m" + seconds + "s";
+ return hours + "h " + mins + "m " + seconds + "s";
}
var days = Math.floor(hours / 24);
hours = hours % 24;
- return days + "d " + hours + "h " + mins + "m " + seconds + "s";
+ return days + "d " + hours + "h " + mins + "m";
}
return "-";
src/web/js/azkaban.exflow.view.js 165(+150 -15)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 1ec6f2a..c95520d 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -545,6 +545,145 @@ azkaban.SvgGraphView = Backbone.View.extend({
}
});
+var executionListView;
+azkaban.ExecutionListView = Backbone.View.extend({
+ events: {
+ },
+ initialize: function(settings) {
+ this.model.bind('change:graph', this.renderJobs, this);
+ this.model.bind('change:update', this.updateJobs, this);
+ },
+ renderJobs: function(evt) {
+ var data = this.model.get("data");
+ var lastTime = data.endTime == -1 ? (new Date()).getTime() : data.endTime;
+ this.updateJobRow(data.nodes);
+ this.updateProgressBar(data);
+ },
+ updateJobs: function(evt) {
+ var data = this.model.get("update");
+ var lastTime = data.endTime == -1 ? (new Date()).getTime() : data.endTime;
+
+ this.updateJobRow(data.nodes);
+ this.updateProgressBar(this.model.get("data"));
+ },
+ updateJobRow: function(nodes) {
+ var executingBody = $("#executableBody");
+ nodes.sort(function(a,b) { return a.startTime - b.startTime; });
+
+ for (var i = 0; i < nodes.length; ++i) {
+ var node = nodes[i];
+ if (node.startTime > -1) {
+ var row = document.getElementById(node.id + "-row");
+ if (!row) {
+ this.addNodeRow(node);
+ }
+
+ $("#" + node.id + "-status").text(node.status);
+
+ var startdate = new Date(node.startTime);
+ $("#" + node.id + "-start").text(getDateFormat(startdate));
+
+ var endTime = node.endTime;
+ if (node.endTime == -1) {
+ $("#" + node.id + "-end").text("-");
+ endTime = node.startTime + 1;
+ }
+ else {
+ var enddate = new Date(node.endTime);
+ $("#" + node.id + "-end").text(getDateFormat(enddate));
+ }
+
+ var progressBar = $("#" + node.id + "-progressbar");
+ for (var j = 0; j < statusList.length; ++j) {
+ var status = statusList[j];
+ progressBar.removeClass(status);
+ }
+ progressBar.addClass(node.status);
+
+ if (node.endTime == -1) {
+ $("#" + node.id + "-elapse").text("0 sec");
+ }
+ else {
+ $("#" + node.id + "-elapse").text(getDuration(node.startTime, node.endTime));
+ }
+ }
+ }
+ },
+ updateProgressBar: function(data) {
+ if(data.startTime == -1) {
+ return;
+ }
+
+ var flowLastTime = data.endTime == -1 ? (new Date()).getTime() : data.endTime;
+ var flowStartTime = data.startTime;
+
+ var outerWidth = $(".outerProgress").css("width");
+ if (outerWidth.substring(outerWidth.length - 2, outerWidth.length) == "px") {
+ outerWidth = outerWidth.substring(0, outerWidth.length - 2);
+ }
+ outerWidth = parseInt(outerWidth);
+
+ var nodes = data.nodes;
+ for (var i = 0; i < nodes.length; ++i) {
+ var node = nodes[i];
+
+ // calculate the progress
+ var diff = flowLastTime - flowStartTime;
+
+ var factor = outerWidth/diff;
+ var left = Math.max((node.startTime-flowStartTime)*factor, 0);
+ var width = Math.max((node.endTime - node.startTime)*factor, 1);
+ width = Math.min(width, outerWidth);
+
+ $("#" + node.id + "-progressbar").css("margin-left", left)
+ $("#" + node.id + "-progressbar").css("width", width);
+ }
+ },
+ addNodeRow: function(node) {
+ var executingBody = $("#executableBody");
+ var tr = document.createElement("tr");
+ var tdName = document.createElement("td");
+ var tdTimeline = document.createElement("td");
+ var tdStart = document.createElement("td");
+ var tdEnd = document.createElement("td");
+ var tdElapse = document.createElement("td");
+ var tdStatus = document.createElement("td");
+ var tdLog = document.createElement("td");
+
+ $(tr).append(tdName);
+ $(tr).append(tdTimeline);
+ $(tr).append(tdStart);
+ $(tr).append(tdEnd);
+ $(tr).append(tdElapse);
+ $(tr).append(tdStatus);
+ $(tr).append(tdLog);
+ $(tr).attr("id", node.id + "-row");
+ $(tdTimeline).attr("id", node.id + "-timeline");
+ $(tdStart).attr("id", node.id + "-start");
+ $(tdEnd).attr("id", node.id + "-end");
+ $(tdElapse).attr("id", node.id + "-elapse");
+ $(tdStatus).attr("id", node.id + "-status");
+
+ var outerProgressBar = document.createElement("div");
+ $(outerProgressBar).addClass("outerProgress");
+
+ var progressBox = document.createElement("div");
+ $(progressBox).attr("id", node.id + "-progressbar");
+ $(progressBox).addClass("progressBox");
+ $(outerProgressBar).append(progressBox);
+ $(tdTimeline).append(outerProgressBar);
+ $(tdTimeline).addClass("timeline");
+
+ var requestURL = contextURL + "/manager?project=" + projectName + "&flow=" + flowName + "&job=" + node.id;
+ var a = document.createElement("a");
+ $(a).attr("href", requestURL);
+ $(a).text(node.id);
+ $(tdName).append(a);
+
+ executingBody.append(tr);
+ }
+});
+
var graphModel;
azkaban.GraphModel = Backbone.Model.extend({});
@@ -600,26 +739,14 @@ var updaterFunction = function() {
$(function() {
var selected;
-
- if (window.location.hash) {
- var hash = window.location.hash;
- if (hash == "#jobslist") {
- selected = "jobslist";
- }
- else if (hash == "#graph") {
- // Redundant, but we may want to change the default.
- selected = "graph";
- }
- else {
- selected = "graph";
- }
- }
- flowTabView = new azkaban.FlowTabView({el:$( '#headertabs'), selectedView: selected });
+
+ flowTabView = new azkaban.FlowTabView({el:$( '#headertabs') });
graphModel = new azkaban.GraphModel();
svgGraphView = new azkaban.SvgGraphView({el:$('#svgDiv'), model: graphModel});
jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel});
statusView = new azkaban.StatusView({el:$('#flow-status'), model: graphModel});
+ executionListView = new azkaban.ExecutionListView({el: $('#jobListView'), model:graphModel});
var requestURL = contextURL + "/executor";
$.get(
@@ -643,6 +770,14 @@ $(function() {
}
graphModel.set({nodeMap: nodeMap});
+
+ if (window.location.hash) {
+ var hash = window.location.hash;
+ if (hash == "#jobslist") {
+ flowTabView.handleJobslistLinkClick();
+ }
+ }
+
setTimeout(function() {updaterFunction()}, 5000);
},
"json"