azkaban-uncached
Changes
src/web/js/azkaban.exflow.view.js 681(+357 -324)
Details
diff --git a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
index 5c4f1d4..7bf96fb 100644
--- a/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/executingflowpage.vm
@@ -17,14 +17,11 @@
<!DOCTYPE html>
<html>
<head>
-#parse( "azkaban/webapp/servlet/velocity/style.vm" )
- <script type="text/javascript" src="${context}/js/jquery/jquery-1.9.1.js"></script>
- <script type="text/javascript" src="${context}/js/jqueryui/jquery-ui-1.10.1.custom.js"></script>
- <script type="text/javascript" src="${context}/js/underscore-1.4.4-min.js"></script>
- <script type="text/javascript" src="${context}/js/namespace.js"></script>
- <script type="text/javascript" src="${context}/js/backbone-0.9.10-min.js"></script>
- <script type="text/javascript" src="${context}/js/jquery.simplemodal-1.4.4.js"></script>
+#parse("azkaban/webapp/servlet/velocity/style2.vm")
+#parse("azkaban/webapp/servlet/velocity/javascript.vm")
+
+ <script type="text/javascript" src="${context}/js/jqueryui/jquery-ui-1.10.1.custom.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.common.utils.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.date.utils.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.context.menu.js"></script>
@@ -47,128 +44,177 @@
var flowId = "${flowid}";
var execId = "${execid}";
</script>
- <link rel="stylesheet" type="text/css" href="${context}/css/jquery-ui-1.10.1.custom.css" />
+ <link rel="stylesheet" type="text/css" href="${context}/css/azkaban-svg.css">
+ <link rel="stylesheet" type="text/css" href="${context}/css/jquery-ui-1.10.1.custom.css">
</head>
<body>
-#set($current_page="all")
-#set($show_schedule="false")
-
-#parse( "azkaban/webapp/servlet/velocity/nav.vm" )
- <div class="messaging"><p id="messageClose">X</p><p id="message"></p></div>
- <div class="content">
-#if($errorMsg)
- <div class="box-error-message">$errorMsg</div>
+
+#set ($current_page="all")
+#set ($show_schedule="false")
+#parse ("azkaban/webapp/servlet/velocity/nav2.vm")
+
+ <div class="container">
+
+#if ($errorMsg)
+ <div class="panel panel-danger">
+ <div class="panel-heading">Error</div>
+ <div class="panel-body">
+ $errorMsg
+ </div>
+ </div>
#else
-#if($error_message != "null")
- <div class="box-error-message">$error_message</div>
-#elseif($success_message != "null")
- <div class="box-success-message">$success_message</div>
-#end
+ #if ($error_message != "null")
+ <div class="alert alert-danger">$error_message</div>
+ #elseif ($success_message != "null")
+ <div class="alert alert-success">$success_message</div>
+ #end
- <div id="all-jobs-content">
- <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>
- <h4><a href="${context}/manager?project=${projectName}&flow=${flowid}">Flow <span>$flowid</span></a></h4>
- <h4 class="separator">></h4>
- <h4><a href="${context}/executor?execid=${execid}">Execution <span>$execid</span></a></h4>
- </div>
+ ## Alert message
+
+ <div class="alert alert-dismissable alert-messaging" id="messaging">
+ <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
+ <p id="messaging-message"></p>
+ </div>
+
+ ## Page header
+
+ <div class="page-header">
+ <h1>
+ <a href="${context}/executor?execid=${execid}">Flow Execution <small>$execid</small></a>
+ </h1>
+ </div>
+
+ ## Breadcrumb
+
+ <ol class="breadcrumb">
+ <li><a href="${context}/manager?project=${projectName}"><strong>Project</strong> $projectName</a></li>
+ <li><a href="${context}/manager?project=${projectName}&flow=${flowid}"><strong>Flow</strong> $flowid</a></li>
+ <li><a href="${context}/executor?execid=${execid}"><strong>Execution</strong> $execid</a></li>
+ </ol>
+
+ ## Flow status
+
+ <div class="well">
+ <div class="row" id="flow-status">
+ <div class="col-lg-6">
+ <p><strong>Status</strong> <span id="flowStatus">-</span></p>
+ <p><strong>Submit User</strong> <span id="submitUser">-</span></p>
</div>
-
- <div id="headertabs" class="headertabs">
- <ul>
- <li><a id="graphViewLink" href="#graph">Graph</a></li>
- <li class="lidivider">|</li>
- <li><a id="jobslistViewLink" href="#jobslist">Job List</a></li>
- <li class="lidivider">|</li>
- <li><a id="flowLogViewLink" href="#log">Flow Log</a></li>
- </ul>
- <ul id="actionsBtns" class="buttons">
- <li><div id="pausebtn" class="btn2">Pause</div></li>
- <li><div id="resumebtn" class="btn2">Resume</div></li>
- <li><div id="cancelbtn" class="btn6">Cancel</div></li>
- <li><div id="retrybtn" class="btn1">Retry Failed</div></li>
- <li><div id="executebtn" class="btn1">Prepare Execution</div></li>
- </ul>
+ <div class="col-lg-6">
+ <p><strong>Start Time</strong> <span id="startTime">-</span></p>
+ <p><strong>End Time</strong> <span id="endTime">-</span></p>
+ <p><strong>Duration</strong> <span id="duration">-</span></p>
</div>
- <div id="graphView">
- <div class="relative">
- <div id="jobList" class="jobList">
- <div id="filterList" class="filterList">
- <input id="filter" class="filter" placeholder=" Job Filter" />
- </div>
- <div id="list" class="list">
- </div>
- <div id="resetPanZoomBtn" class="btn5 resetPanZoomBtn" >Reset Pan Zoom</div>
- </div>
- <div id="svgDiv" class="svgDiv">
- <svg id="svgGraph" class="svgGraph" xmlns="http://www.w3.org/2000/svg" version="1.1" shape-rendering="optimize-speed" text-rendering="optimize-speed" >
- </svg>
+ </div>
+ </div>
+
+ ## Tabs and buttons.
+
+ <div class="row">
+ <div class="col-lg-8">
+ <ul class="nav nav-tabs" id="headertabs">
+ <li id="graphViewLink"><a href="#graph">Graph</a></li>
+ <li id="jobslistViewLink"><a href="#jobslist">Job List</a></li>
+ <li id="flowLogViewLink"><a href="#log">Flow Log</a></li>
+ </ul>
+ </div>
+ <div class="col-lg-4">
+ <button id="pausebtn" class="btn btn-primary">Pause</button>
+ <button id="resumebtn" class="btn btn-primary">Resume</button>
+ <button id="cancelbtn" class="btn btn-danger">Cancel</button>
+ <button id="retrybtn" class="btn btn-success">Retry Failed</button>
+ <button id="executebtn" class="btn btn-success">Prepare Execution</button>
+ </div>
+ </div>
+
+ ## Graph View
+
+ <div class="row" id="graphView">
+ <div class="col-lg-4">
+ <div class="panel panel-default" id="jobList">
+ <div class="panel-heading">
+ <div class="pull-right">
+ <button type="button" class="btn btn-xs btn-default" id="resetPanZoomBtn">Reset Pan Zoom</button>
</div>
+ Jobs
</div>
- </div>
- <div id="jobListView" class="executionInfo">
- <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 id="flowLogView" class="logView">
- <div class="logHeader"><div class="logButtonRow"><div id="updateLogBtn" class="btn7">Refresh</div></div></div>
- <div class="logViewer">
- <pre id="logSection" class="log"></pre>
+ <div class="panel-body" id="filterList">
+ <input id="filter" type="text" placeholder="Job Filter">
+ <div id="list"></div>
</div>
</div>
</div>
-
- <div id="flow-status">
- <table class="status">
- <tr><td class="first">Status</td><td id="flowStatus">-</td></tr>
- <tr><td class="first">Submit User</td><td id="submitUser">-</td></tr>
- </table>
- <table class="time">
- <tr><td class="first">Start Time</td><td id="startTime">-</td></tr>
- <tr><td class="first">End Time</td><td id="endTime">-</td></tr>
- <tr><td class="first">Duration</td><td id="duration">-</td></tr>
+ <div class="col-lg-8">
+ <div id="svgDiv" class="well">
+ <svg id="svgGraph" class="svgGraph" xmlns="http://www.w3.org/2000/svg" version="1.1" shape-rendering="optimize-speed" text-rendering="optimize-speed" >
+ </svg>
+ </div>
+ </div>
+ </div>
+
+ ## Job List View
+
+ <div class="row" id="jobListView">
+ <div class="col-lg-12">
+ <table class="table table-striped table-bordered">
+ <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>
-#parse( "azkaban/webapp/servlet/velocity/flowexecutionpanel.vm" )
-#end
- </div>
+ ## Flow Log View
-
- <div id="messageDialog" class="modal">
- <h3 id="messageTitle">Error</h3>
- <div class="messageDiv">
- <p id="messageBox"></p>
+ <div class="row" id="flowLogView">
+ <div class="col-lg-12">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="pull-right">
+ <button type="button" id="updateLogBtn" class="btn btn-xs btn-default">Refresh</button>
+ </div>
+ Flow log
+ </div>
+ <div class="panel-body">
+ <pre id="logSection" class="log"></pre>
+ </div>
+ </div>
+ </div>
</div>
- </div>
-
- <div id="invalid-session" class="modal">
- <h3>Invalid Session</h3>
- <p>Session has expired. Please re-login.</p>
- <div class="actions">
- <a class="yes btn2" id="login-btn" href="#">Re-login</a>
+
+ ## Error message message dialog.
+
+ <div class="modal fade" id="messageDialog">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header" id="messageTitle">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title">Error</h4>
+ </div>
+ <div class="modal-body" id="messageDiv">
+ <p id="messageBox"></p>
+ </div>
+ </div>
+ </div>
</div>
+
+ <div id="contextMenu"></div>
+
+ #parse ("azkaban/webapp/servlet/velocity/invalidsessionmodal.vm")
+ #parse ("azkaban/webapp/servlet/velocity/flowexecutionpanel.vm")
+ #parse ("azkaban/webapp/servlet/velocity/messagedialog.vm")
+#end
+#parse ("azkaban/webapp/servlet/velocity/footer.vm")
</div>
-
- <div id="contextMenu">
- </div>
- #parse( "azkaban/webapp/servlet/velocity/messagedialog.vm" )
</body>
</html>
-
diff --git a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
index 6afe415..8f18779 100644
--- a/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/flowpage.vm
@@ -116,7 +116,7 @@
</div>
Jobs
</div>
- <div class="panel-body">
+ <div class="panel-body" id="filterList">
<input id="filter" type="text" placeholder="Job Filter">
<div id="list"></div>
</div>
@@ -164,25 +164,7 @@
<div id="contextMenu">
</div>
- ## Modal dialog to be displayed when the user sesion is invalid.
-
- <div class="modal fade" id="invalid-session-modal">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
- <h4 class="modal-title">Invalid Session</h4>
- </div>
- <div class="modal-body">
- <p>Session has expired. Please re-login.</p>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-primary" id="login-btn">Re-login</button>
- </div>
- </div>
- </div>
- </div>
-
+ #parse ("azkaban/webapp/servlet/velocity/invalidsessionmodal.vm")
#parse ("azkaban/webapp/servlet/velocity/flowexecutionpanel.vm")
#parse ("azkaban/webapp/servlet/velocity/messagedialog.vm")
#end
diff --git a/src/java/azkaban/webapp/servlet/velocity/invalidsessionmodal.vm b/src/java/azkaban/webapp/servlet/velocity/invalidsessionmodal.vm
new file mode 100644
index 0000000..f0875e4
--- /dev/null
+++ b/src/java/azkaban/webapp/servlet/velocity/invalidsessionmodal.vm
@@ -0,0 +1,34 @@
+#*
+ * Copyright 2012 LinkedIn Corp.
+ *
+ * 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.
+*#
+
+ ## Modal dialog to be displayed when the user sesion is invalid.
+
+ <div class="modal fade" id="invalid-session-modal">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title">Invalid Session</h4>
+ </div>
+ <div class="modal-body">
+ <p>Session has expired. Please re-login.</p>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-primary" id="login-btn">Re-login</button>
+ </div>
+ </div>
+ </div>
+ </div>
diff --git a/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
index 81a116a..5f982b2 100644
--- a/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/joblogpage.vm
@@ -107,7 +107,7 @@
<div class="modal-content">
<div class="modal-header" id="messageTitle">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
- <h4 class="modal-title">Upload Project Files</h4>
+ <h4 class="modal-title">Error</h4>
</div>
<div class="modal-body" id="messageDiv">
<p id="messageBox"></p>
src/web/js/azkaban.exflow.view.js 681(+357 -324)
diff --git a/src/web/js/azkaban.exflow.view.js b/src/web/js/azkaban.exflow.view.js
index 377703b..b571b56 100644
--- a/src/web/js/azkaban.exflow.view.js
+++ b/src/web/js/azkaban.exflow.view.js
@@ -28,12 +28,12 @@ var handleJobMenuClick = function(action, el, pos) {
}
var statusView;
-azkaban.StatusView= Backbone.View.extend({
- initialize : function(settings) {
+azkaban.StatusView = Backbone.View.extend({
+ initialize: function(settings) {
this.model.bind('change:graph', this.render, this);
this.model.bind('change:update', this.statusUpdate, this);
},
- render : function(evt) {
+ render: function(evt) {
var data = this.model.get("data");
var user = data.submitUser;
@@ -41,7 +41,8 @@ azkaban.StatusView= Backbone.View.extend({
this.statusUpdate(evt);
},
- statusUpdate : function(evt) {
+
+ statusUpdate: function(evt) {
var data = this.model.get("data");
statusItem = $("#flowStatus");
@@ -83,202 +84,188 @@ azkaban.StatusView= Backbone.View.extend({
});
var flowTabView;
-azkaban.FlowTabView= Backbone.View.extend({
- events : {
- "click #graphViewLink" : "handleGraphLinkClick",
- "click #jobslistViewLink" : "handleJobslistLinkClick",
- "click #flowLogViewLink" : "handleLogLinkClick",
- "click #cancelbtn" : "handleCancelClick",
- "click #executebtn" : "handleRestartClick",
- "click #pausebtn" : "handlePauseClick",
- "click #resumebtn" : "handleResumeClick",
- "click #retrybtn" : "handleRetryClick"
- },
- initialize : function(settings) {
- $("#cancelbtn").hide();
- $("#executebtn").hide();
- $("#pausebtn").hide();
- $("#resumebtn").hide();
- $("#retrybtn").hide();
-
- this.model.bind('change:graph', this.handleFlowStatusChange, this);
- this.model.bind('change:update', this.handleFlowStatusChange, this);
+azkaban.FlowTabView = Backbone.View.extend({
+ events: {
+ "click #graphViewLink": "handleGraphLinkClick",
+ "click #jobslistViewLink": "handleJobslistLinkClick",
+ "click #flowLogViewLink": "handleLogLinkClick",
+ "click #cancelbtn": "handleCancelClick",
+ "click #executebtn": "handleRestartClick",
+ "click #pausebtn": "handlePauseClick",
+ "click #resumebtn": "handleResumeClick",
+ "click #retrybtn": "handleRetryClick"
+ },
- var selectedView = settings.selectedView;
- if (selectedView == "jobslist") {
- this.handleJobslistLinkClick();
- }
- else {
- this.handleGraphLinkClick();
- }
- },
- render: function() {
- console.log("render graph");
- },
- handleGraphLinkClick: function(){
- $("#jobslistViewLink").removeClass("selected");
- $("#graphViewLink").addClass("selected");
- $("#flowLogViewLink").removeClass("selected");
-
- $("#jobListView").hide();
- $("#graphView").show();
- $("#flowLogView").hide();
- },
- handleJobslistLinkClick: function() {
- $("#graphViewLink").removeClass("selected");
- $("#jobslistViewLink").addClass("selected");
- $("#flowLogViewLink").removeClass("selected");
-
- $("#graphView").hide();
- $("#jobListView").show();
- $("#flowLogView").hide();
- },
- handleLogLinkClick: function() {
- $("#graphViewLink").removeClass("selected");
- $("#jobslistViewLink").removeClass("selected");
- $("#flowLogViewLink").addClass("selected");
-
- $("#graphView").hide();
- $("#jobListView").hide();
- $("#flowLogView").show();
- },
- handleFlowStatusChange: function() {
- var data = this.model.get("data");
- $("#cancelbtn").hide();
- $("#executebtn").hide();
- $("#pausebtn").hide();
- $("#resumebtn").hide();
- $("#retrybtn").hide();
-
- if(data.status=="SUCCEEDED") {
- $("#executebtn").show();
- }
- else if (data.status=="FAILED") {
- $("#executebtn").show();
- }
- else if (data.status=="FAILED_FINISHING") {
- $("#cancelbtn").show();
- $("#executebtn").hide();
- $("#retrybtn").show();
- }
- else if (data.status=="RUNNING") {
- $("#cancelbtn").show();
- $("#pausebtn").show();
- }
- else if (data.status=="PAUSED") {
- $("#cancelbtn").show();
- $("#resumebtn").show();
- }
- else if (data.status=="WAITING") {
- $("#cancelbtn").show();
- }
- else if (data.status=="KILLED") {
- $("#executebtn").show();
- }
- },
- handleCancelClick : function(evt) {
- var requestURL = contextURL + "/executor";
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"cancelFlow"},
- function(data) {
- console.log("cancel clicked");
- if (data.error) {
- showDialog("Error", data.error);
- }
- else {
- showDialog("Cancelled", "Flow has been cancelled.");
-
- setTimeout(function() {updateStatus();}, 1100);
- }
- }
- );
- },
- handleRetryClick : function(evt) {
- var graphData = graphModel.get("data");
-
- var requestURL = contextURL + "/executor";
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"retryFailedJobs"},
- function(data) {
- console.log("cancel clicked");
- if (data.error) {
- showDialog("Error", data.error);
- }
- else {
- showDialog("Retry", "Flow has been retried.");
- setTimeout(function() {updateStatus();}, 1100);
- }
- }
- );
- },
- handleRestartClick : function(evt) {
- var data = graphModel.get("data");
- var nodes = data.nodes;
-
- var executingData = {
- project: projectName,
- ajax: "executeFlow",
- flow: flowId,
- execid: execId
- };
-
- flowExecuteDialogView.show(executingData);
- },
- handlePauseClick : function(evt) {
- var requestURL = contextURL + "/executor";
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"pauseFlow"},
- function(data) {
- console.log("pause clicked");
- if (data.error) {
- showDialog("Error", data.error);
- }
- else {
- showDialog("Paused", "Flow has been paused.");
-
- setTimeout(function() {updateStatus();}, 1100);
- }
- }
- );
- },
- handleResumeClick : function(evt) {
- var requestURL = contextURL + "/executor";
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"resumeFlow"},
- function(data) {
- console.log("pause clicked");
- if (data.error) {
- showDialog("Error", data.error);
- }
- else {
- showDialog("Resumed", "Flow has been resumed.");
- setTimeout(function() {updateStatus();}, 1100);
- }
- }
- );
- }
+ initialize: function(settings) {
+ $("#cancelbtn").hide();
+ $("#executebtn").hide();
+ $("#pausebtn").hide();
+ $("#resumebtn").hide();
+ $("#retrybtn").hide();
+
+ this.model.bind('change:graph', this.handleFlowStatusChange, this);
+ this.model.bind('change:update', this.handleFlowStatusChange, this);
+
+ var selectedView = settings.selectedView;
+ if (selectedView == "jobslist") {
+ this.handleJobslistLinkClick();
+ }
+ else {
+ this.handleGraphLinkClick();
+ }
+ },
+
+ render: function() {
+ console.log("render graph");
+ },
+
+ handleGraphLinkClick: function(){
+ $("#jobslistViewLink").removeClass("active");
+ $("#graphViewLink").addClass("active");
+ $("#flowLogViewLink").removeClass("active");
+
+ $("#jobListView").hide();
+ $("#graphView").show();
+ $("#flowLogView").hide();
+ },
+
+ handleJobslistLinkClick: function() {
+ $("#graphViewLink").removeClass("active");
+ $("#jobslistViewLink").addClass("active");
+ $("#flowLogViewLink").removeClass("active");
+
+ $("#graphView").hide();
+ $("#jobListView").show();
+ $("#flowLogView").hide();
+ },
+
+ handleLogLinkClick: function() {
+ $("#graphViewLink").removeClass("active");
+ $("#jobslistViewLink").removeClass("active");
+ $("#flowLogViewLink").addClass("active");
+
+ $("#graphView").hide();
+ $("#jobListView").hide();
+ $("#flowLogView").show();
+ },
+
+ handleFlowStatusChange: function() {
+ var data = this.model.get("data");
+ $("#cancelbtn").hide();
+ $("#executebtn").hide();
+ $("#pausebtn").hide();
+ $("#resumebtn").hide();
+ $("#retrybtn").hide();
+
+ if (data.status == "SUCCEEDED") {
+ $("#executebtn").show();
+ }
+ else if (data.status == "FAILED") {
+ $("#executebtn").show();
+ }
+ else if (data.status == "FAILED_FINISHING") {
+ $("#cancelbtn").show();
+ $("#executebtn").hide();
+ $("#retrybtn").show();
+ }
+ else if (data.status == "RUNNING") {
+ $("#cancelbtn").show();
+ $("#pausebtn").show();
+ }
+ else if (data.status == "PAUSED") {
+ $("#cancelbtn").show();
+ $("#resumebtn").show();
+ }
+ else if (data.status == "WAITING") {
+ $("#cancelbtn").show();
+ }
+ else if (data.status == "KILLED") {
+ $("#executebtn").show();
+ }
+ },
+
+ handleCancelClick: function(evt) {
+ var requestURL = contextURL + "/executor";
+ var requestData = {"execid": execId, "ajax": "cancelFlow"};
+ var successHandler = function(data) {
+ console.log("cancel clicked");
+ if (data.error) {
+ showDialog("Error", data.error);
+ }
+ else {
+ showDialog("Cancelled", "Flow has been cancelled.");
+ setTimeout(function() {updateStatus();}, 1100);
+ }
+ };
+ ajaxCall(requestURL, requestData, successHandler);
+ },
+
+ handleRetryClick: function(evt) {
+ var graphData = graphModel.get("data");
+ var requestURL = contextURL + "/executor";
+ var requestData = {"execid": execId, "ajax":"retryFailedJobs"};
+ var successHandler = function(data) {
+ console.log("cancel clicked");
+ if (data.error) {
+ showDialog("Error", data.error);
+ }
+ else {
+ showDialog("Retry", "Flow has been retried.");
+ setTimeout(function() {updateStatus();}, 1100);
+ }
+ };
+ ajaxCall(requestURL, requestData, successHandler);
+ },
+
+ handleRestartClick: function(evt) {
+ var data = graphModel.get("data");
+ var nodes = data.nodes;
+ var executingData = {
+ project: projectName,
+ ajax: "executeFlow",
+ flow: flowId,
+ execid: execId
+ };
+ flowExecuteDialogView.show(executingData);
+ },
+
+ handlePauseClick: function(evt) {
+ var requestURL = contextURL + "/executor";
+ var requestData = {"execid": execId, "ajax":"pauseFlow"};
+ var successHandler = function(data) {
+ console.log("pause clicked");
+ if (data.error) {
+ showDialog("Error", data.error);
+ }
+ else {
+ showDialog("Paused", "Flow has been paused.");
+ setTimeout(function() {updateStatus();}, 1100);
+ }
+ };
+ ajaxCall(requestURL, requestData, successHandler);
+ },
+
+ handleResumeClick: function(evt) {
+ var requestURL = contextURL + "/executor";
+ var requestData = {"execid": execId, "ajax":"resumeFlow"};
+ var successHandler = function(data) {
+ console.log("pause clicked");
+ if (data.error) {
+ showDialog("Error", data.error);
+ }
+ else {
+ showDialog("Resumed", "Flow has been resumed.");
+ setTimeout(function() {updateStatus();}, 1100);
+ }
+ };
+ ajaxCall(requestURL, requestData, successHandler);
+ }
});
var showDialog = function(title, message) {
- $('#messageTitle').text(title);
-
- $('#messageBox').text(message);
-
- $('#messageDialog').modal({
- closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>",
- position: ["20%",],
- containerId: 'confirm-container',
- containerCss: {
- 'height': '220px',
- 'width': '565px'
- },
- onShow: function (dialog) {
- }
- });
+ $('#messageTitle').text(title);
+ $('#messageBox').text(message);
+ $('#messageDialog').modal();
}
var jobListView;
@@ -287,19 +274,22 @@ var mainSvgGraphView;
var executionListView;
azkaban.ExecutionListView = Backbone.View.extend({
events: {
-// "click .progressBox" : "handleProgressBoxClick"
+ //"click .progressBox": "handleProgressBoxClick"
},
+
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);
},
-/* handleProgressBoxClick: function(evt) {
+
+ /*handleProgressBoxClick: function(evt) {
var target = evt.currentTarget;
var job = target.job;
var attempt = target.attempt;
@@ -317,6 +307,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
contextMenuView.show(evt, menu);
},*/
+
updateJobs: function(evt) {
var data = this.model.get("update");
var lastTime = data.endTime == -1 ? (new Date()).getTime() : data.endTime;
@@ -324,6 +315,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
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; });
@@ -384,7 +376,7 @@ azkaban.ExecutionListView = Backbone.View.extend({
}
if (node.endTime == -1) {
-// $("#" + node.id + "-elapse").text("0 sec");
+ //$("#" + node.id + "-elapse").text("0 sec");
$("#" + nodeId + "-elapse").text(getDuration(node.startTime, (new Date()).getTime()));
}
else {
@@ -393,8 +385,9 @@ azkaban.ExecutionListView = Backbone.View.extend({
}
}
},
+
updateProgressBar: function(data) {
- if(data.startTime == -1) {
+ if (data.startTime == -1) {
return;
}
@@ -424,24 +417,24 @@ azkaban.ExecutionListView = Backbone.View.extend({
// Add all the attempts
if (node.pastAttempts) {
- var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.id + "&attempt=" + node.pastAttempts.length;
+ var logURL = contextURL + "/executor?execid=" + execId + "&job=" + node.id + "&attempt=" + node.pastAttempts.length;
var aId = node.id + "-log-link";
$("#" + aId).attr("href", logURL);
elem.attempt = node.pastAttempts.length;
// Calculate the node attempt bars
- for(var p = 0; p < node.pastAttempts.length; ++p) {
+ for (var p = 0; p < node.pastAttempts.length; ++p) {
var pastAttempt = node.pastAttempts[p];
var pastAttemptBox = $("#" + nodeId + "-progressbar-" + p);
var left = (pastAttempt.startTime - flowStartTime)*factor;
- var width = Math.max((pastAttempt.endTime - pastAttempt.startTime)*factor, 3);
+ var width = Math.max((pastAttempt.endTime - pastAttempt.startTime)*factor, 3);
var margin = left - offsetLeft;
$(pastAttemptBox).css("margin-left", left - offsetLeft);
$(pastAttemptBox).css("width", width);
- $(pastAttemptBox).attr("title", "attempt:" + p + " start:" + getHourMinSec(new Date(pastAttempt.startTime)) + " end:" + getHourMinSec(new Date(pastAttempt.endTime)));
+ $(pastAttemptBox).attr("title", "attempt:" + p + " start:" + getHourMinSec(new Date(pastAttempt.startTime)) + " end:" + getHourMinSec(new Date(pastAttempt.endTime)));
offsetLeft += width + margin;
}
}
@@ -454,9 +447,10 @@ azkaban.ExecutionListView = Backbone.View.extend({
elem.css("margin-left", left)
elem.css("width", width);
- elem.attr("title", "attempt:" + elem.attempt + " start:" + getHourMinSec(new Date(node.startTime)) + " end:" + getHourMinSec(new Date(node.endTime)));
+ elem.attr("title", "attempt:" + elem.attempt + " start:" + getHourMinSec(new Date(node.startTime)) + " end:" + getHourMinSec(new Date(node.endTime)));
}
},
+
addNodeRow: function(node) {
var executingBody = $("#executableBody");
var tr = document.createElement("tr");
@@ -536,31 +530,36 @@ azkaban.FlowLogView = Backbone.View.extend({
var model = this.model;
console.log("fetchLogs offset is " + offset)
- $.ajax({async:false,
- url:requestURL,
- data:{"execid": execId, "ajax":"fetchExecFlowLogs", "offset": offset, "length": 50000},
- success:
- function(data) {
- console.log("fetchLogs");
- if (data.error) {
- console.log(data.error);
+ $.ajax({
+ async: false,
+ url: requestURL,
+ data: {
+ "execid": execId,
+ "ajax": "fetchExecFlowLogs",
+ "offset": offset,
+ "length": 50000
+ },
+ success: function(data) {
+ console.log("fetchLogs");
+ if (data.error) {
+ console.log(data.error);
+ }
+ else {
+ var log = $("#logSection").text();
+ if (!log) {
+ log = data.data;
}
else {
- var log = $("#logSection").text();
- if (!log) {
- log = data.data;
- }
- else {
- log += data.data;
- }
-
- var newOffset = data.offset + data.length;
-
- $("#logSection").text(log);
- model.set({"offset": newOffset, "log": log});
- $(".logViewer").scrollTop(9999);
+ log += data.data;
}
+
+ var newOffset = data.offset + data.length;
+
+ $("#logSection").text(log);
+ model.set({"offset": newOffset, "log": log});
+ $(".logViewer").scrollTop(9999);
}
+ }
});
}
});
@@ -576,48 +575,57 @@ var updateStatus = function() {
var oldData = graphModel.get("data");
var nodeMap = graphModel.get("nodeMap");
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"fetchexecflowupdate", "lastUpdateTime": updateTime},
- function(data) {
- console.log("data updated");
- updateTime = data.updateTime;
- oldData.submitTime = data.submitTime;
- oldData.startTime = data.startTime;
- oldData.endTime = data.endTime;
- oldData.status = data.status;
-
- for (var i = 0; i < data.nodes.length; ++i) {
- var node = data.nodes[i];
- var oldNode = nodeMap[node.id];
- oldNode.startTime = node.startTime;
- oldNode.updateTime = node.updateTime;
- oldNode.endTime = node.endTime;
- oldNode.status = node.status;
- oldNode.attempt = node.attempt;
- if (oldNode.attempt > 0) {
- oldNode.pastAttempts = node.pastAttempts;
- }
- }
-
- graphModel.set({"update": data});
- graphModel.trigger("change:update");
- });
+ var requestData = {
+ "execid": execId,
+ "ajax": "fetchexecflowupdate",
+ "lastUpdateTime": updateTime
+ };
+
+ var successHandler = function(data) {
+ console.log("data updated");
+ updateTime = data.updateTime;
+ oldData.submitTime = data.submitTime;
+ oldData.startTime = data.startTime;
+ oldData.endTime = data.endTime;
+ oldData.status = data.status;
+
+ for (var i = 0; i < data.nodes.length; ++i) {
+ var node = data.nodes[i];
+ var oldNode = nodeMap[node.id];
+ oldNode.startTime = node.startTime;
+ oldNode.updateTime = node.updateTime;
+ oldNode.endTime = node.endTime;
+ oldNode.status = node.status;
+ oldNode.attempt = node.attempt;
+ if (oldNode.attempt > 0) {
+ oldNode.pastAttempts = node.pastAttempts;
+ }
+ }
+
+ graphModel.set({"update": data});
+ graphModel.trigger("change:update");
+ };
+ ajaxCall(requestURL, requestData, successHandler);
}
var updateTime = -1;
var updaterFunction = function() {
var oldData = graphModel.get("data");
- var keepRunning = oldData.status != "SUCCEEDED" && oldData.status != "FAILED" && oldData.status != "KILLED";
+ var keepRunning =
+ oldData.status != "SUCCEEDED" &&
+ oldData.status != "FAILED" &&
+ oldData.status != "KILLED";
if (keepRunning) {
updateStatus();
var data = graphModel.get("data");
- if (data.status == "UNKNOWN" || data.status == "WAITING" || data.status == "PREPARING") {
+ if (data.status == "UNKNOWN" ||
+ data.status == "WAITING" ||
+ data.status == "PREPARING") {
setTimeout(function() {updaterFunction();}, 1000);
}
- else if (data.status != "SUCCEEDED" && data.status != "FAILED" ) {
+ else if (data.status != "SUCCEEDED" && data.status != "FAILED") {
// 5 sec updates
setTimeout(function() {updaterFunction();}, 5000);
}
@@ -632,7 +640,10 @@ var updaterFunction = function() {
var logUpdaterFunction = function() {
var oldData = graphModel.get("data");
- var keepRunning = oldData.status != "SUCCEEDED" && oldData.status != "FAILED" && oldData.status != "KILLED";
+ var keepRunning =
+ oldData.status != "SUCCEEDED" &&
+ oldData.status != "FAILED" &&
+ oldData.status != "KILLED";
if (keepRunning) {
// update every 30 seconds for the logs until finished
flowLogView.handleUpdate();
@@ -650,9 +661,9 @@ var exNodeClickCallback = function(event) {
var visualizerURL = contextURL + "/pigvisualizer?execid=" + execId + "&jobid=" + jobId;
var menu = [
- {title: "Open Job...", callback: function() {window.location.href = requestURL;}},
- {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
- {title: "Visualize Job...", callback: function() {window.location.href = visualizerURL;}}
+ {title: "Open Job...", callback: function() {window.location.href = requestURL;}},
+ {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
+ {title: "Visualize Job...", callback: function() {window.location.href = visualizerURL;}}
];
contextMenuView.show(event, menu);
@@ -665,9 +676,9 @@ var exJobClickCallback = function(event) {
var visualizerURL = contextURL + "/pigvisualizer?execid=" + execId + "&jobid=" + jobId;
var menu = [
- {title: "Open Job...", callback: function() {window.location.href = requestURL;}},
- {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
- {title: "Visualize Job...", callback: function() {window.location.href = visualizerURL;}}
+ {title: "Open Job...", callback: function() {window.location.href = requestURL;}},
+ {title: "Open Job in New Window...", callback: function() {window.open(requestURL);}},
+ {title: "Visualize Job...", callback: function() {window.location.href = visualizerURL;}}
];
contextMenuView.show(event, menu);
@@ -700,8 +711,8 @@ var attemptRightClick = function(event) {
var requestURL = contextURL + "/executor?project=" + projectName + "&execid=" + execId + "&job=" + job + "&attempt=" + attempt;
var menu = [
- {title: "Open Attempt Log...", callback: function() {window.location.href=requestURL;}},
- {title: "Open Attempt Log in New Window...", callback: function() {window.open(requestURL);}}
+ {title: "Open Attempt Log...", callback: function() {window.location.href=requestURL;}},
+ {title: "Open Attempt Log in New Window...", callback: function() {window.open(requestURL);}}
];
contextMenuView.show(event, menu);
@@ -714,66 +725,88 @@ $(function() {
graphModel = new azkaban.GraphModel();
logModel = new azkaban.LogModel();
- flowTabView = new azkaban.FlowTabView({el:$( '#headertabs'), model: graphModel});
- mainSvgGraphView = new azkaban.SvgGraphView({el:$('#svgDiv'), model: graphModel, rightClick: { "node": exNodeClickCallback, "edge": exEdgeClickCallback, "graph": exGraphClickCallback }});
- jobsListView = new azkaban.JobListView({el:$('#jobList'), model: graphModel, contextMenuCallback: exJobClickCallback});
- flowLogView = new azkaban.FlowLogView({el:$('#flowLogView'), model: logModel});
- statusView = new azkaban.StatusView({el:$('#flow-status'), model: graphModel});
+ flowTabView = new azkaban.FlowTabView({
+ el: $('#headertabs'),
+ model: graphModel
+ });
+ mainSvgGraphView = new azkaban.SvgGraphView({
+ el: $('#svgDiv'),
+ model: graphModel,
+ rightClick: {
+ "node": exNodeClickCallback,
+ "edge": exEdgeClickCallback,
+ "graph": exGraphClickCallback
+ }
+ });
+ jobsListView = new azkaban.JobListView({
+ el: $('#jobList'),
+ model: graphModel,
+ contextMenuCallback: exJobClickCallback
+ });
+ flowLogView = new azkaban.FlowLogView({
+ el: $('#flowLogView'),
+ model: logModel
+ });
+ statusView = new azkaban.StatusView({
+ el: $('#flow-status'),
+ model: graphModel
+ });
- executionListView = new azkaban.ExecutionListView({el: $('#jobListView'), model:graphModel});
+ executionListView = new azkaban.ExecutionListView({
+ el: $('#jobListView'),
+ model: graphModel
+ });
var requestURL = contextURL + "/executor";
-
- ajaxCall(
- requestURL,
- {"execid": execId, "ajax":"fetchexecflow"},
- function(data) {
- console.log("data fetched");
- graphModel.set({data: data});
- graphModel.set({disabled: {}});
- graphModel.trigger("change:graph");
-
- updateTime = Math.max(updateTime, data.submitTime);
- updateTime = Math.max(updateTime, data.startTime);
- updateTime = Math.max(updateTime, data.endTime);
-
- var nodeMap = {};
- for (var i = 0; i < data.nodes.length; ++i) {
- var node = data.nodes[i];
- nodeMap[node.id] = node;
- updateTime = Math.max(updateTime, node.startTime);
- updateTime = Math.max(updateTime, node.endTime);
- }
- for (var i = 0; i < data.edges.length; ++i) {
- var edge = data.edges[i];
-
- if (!nodeMap[edge.target].in) {
- nodeMap[edge.target].in = {};
- }
- var targetInMap = nodeMap[edge.target].in;
- targetInMap[edge.from] = nodeMap[edge.from];
-
- if (!nodeMap[edge.from].out) {
- nodeMap[edge.from].out = {};
- }
- var sourceOutMap = nodeMap[edge.from].out;
- sourceOutMap[edge.target] = nodeMap[edge.target];
- }
-
- graphModel.set({nodeMap: nodeMap});
-
- if (window.location.hash) {
- var hash = window.location.hash;
- if (hash == "#jobslist") {
- flowTabView.handleJobslistLinkClick();
- }
- else if (hash == "#log") {
- flowTabView.handleLogLinkClick();
- }
- }
-
- updaterFunction();
- logUpdaterFunction();
- }
- );
+ var requestData = {"execid": execId, "ajax":"fetchexecflow"};
+ var successHandler = function(data) {
+ console.log("data fetched");
+ graphModel.set({data: data});
+ graphModel.set({disabled: {}});
+ graphModel.trigger("change:graph");
+
+ updateTime = Math.max(updateTime, data.submitTime);
+ updateTime = Math.max(updateTime, data.startTime);
+ updateTime = Math.max(updateTime, data.endTime);
+
+ var nodeMap = {};
+ for (var i = 0; i < data.nodes.length; ++i) {
+ var node = data.nodes[i];
+ nodeMap[node.id] = node;
+ updateTime = Math.max(updateTime, node.startTime);
+ updateTime = Math.max(updateTime, node.endTime);
+ }
+ for (var i = 0; i < data.edges.length; ++i) {
+ var edge = data.edges[i];
+
+ if (!nodeMap[edge.target].in) {
+ nodeMap[edge.target].in = {};
+ }
+ var targetInMap = nodeMap[edge.target].in;
+ targetInMap[edge.from] = nodeMap[edge.from];
+
+ if (!nodeMap[edge.from].out) {
+ nodeMap[edge.from].out = {};
+ }
+ var sourceOutMap = nodeMap[edge.from].out;
+ sourceOutMap[edge.target] = nodeMap[edge.target];
+ }
+
+ graphModel.set({nodeMap: nodeMap});
+ if (window.location.hash) {
+ var hash = window.location.hash;
+ if (hash == "#jobslist") {
+ flowTabView.handleJobslistLinkClick();
+ }
+ else if (hash == "#log") {
+ flowTabView.handleLogLinkClick();
+ }
+ }
+ else {
+ flowTabView.handleGraphLinkClick();
+ }
+ updaterFunction();
+ logUpdaterFunction();
+ };
+ ajaxCall(requestURL, requestData, successHandler);
});