You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@storm.apache.org by bo...@apache.org on 2018/08/03 20:45:52 UTC

[03/36] storm git commit: STORM-1311: UI Migration from clj to java

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/js/visualization.js
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/js/visualization.js b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/js/visualization.js
new file mode 100644
index 0000000..ced984d
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/js/visualization.js
@@ -0,0 +1,367 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+var visNS = {
+    // Update / refresh setting
+    shouldUpdate: true,
+    updateFreqMs: 30000,
+
+    // Holds our network
+    network: null,
+
+    // Holds nodes and edge definitions
+    nodes: new vis.DataSet(),
+    edges: new vis.DataSet(),
+
+    // References our visualization container element
+    networkContainer: null,
+
+    // Holds map of Sanitized Stream Id => Stream Id
+    availableStreamsHash: { },
+
+    // vis.js options
+    options: {
+        edges:{
+            arrows: {
+                to: {enabled: true, scaleFactor:1}
+            },
+            hoverWidth: 1.5,
+            shadow:{
+                enabled: true,
+                color: 'rgba(0,0,0,0.5)',
+                size:10,
+                x:5,
+                y:5
+            },
+            smooth: {
+                type: "continuous",
+                forceDirection: "none"
+            }
+        },
+        nodes: {
+            color: {
+                border: '#2B7CE9',
+                background: '#97C2FC',
+                highlight: {
+                    border: '#2B7CE9',
+                    background: '#D2E5FF'
+                },
+                hover: {
+                    border: '#2B7CE9',
+                    background: '#D2E5FF'
+                }
+            },
+            shadow:{
+              enabled: true,
+              color: 'rgba(0,0,0,0.5)',
+              size:10,
+              x:5,
+              y:5
+            },
+        },
+        physics:{
+            enabled: false
+        },
+        layout: {
+            randomSeed: 31337,
+            improvedLayout:true,
+            hierarchical: {
+                enabled: true,
+                levelSeparation: 150,
+                nodeSpacing: 300,
+                treeSpacing: 200,
+                blockShifting: true,
+                edgeMinimization: true,
+                parentCentralization: true,
+                direction: 'UD',        // UD, DU, LR, RL
+                sortMethod: 'directed'   // hubsize, directed
+            }
+        },
+        interaction: {
+            navigationButtons: false
+        }
+    }
+};
+
+function parseResponse(json) {
+    console.log("Updating network");
+    // parse json
+    for (var componentId in json) {
+        parseNode(json[componentId], componentId);
+    }
+
+    // Create network if it does not exist yet
+    if (visNS.network == null) {
+        createNetwork()
+    }
+}
+
+function createNetwork() {
+    var data = {
+        "nodes": visNS.nodes,
+        "edges": visNS.edges
+    };
+    // Create network
+    visNS.network = new vis.Network(visNS.networkContainer, data, visNS.options);
+
+    // Create event handlers
+    visNS.network.on("click", function (params) {
+        handleClickEvent(params);
+    });
+    visNS.network.on("deselectNode", function(params) {
+        handleNodeClickEvent(null);
+    });
+
+    // Then disable layout
+    visNS.network.setOptions({layout: {hierarchical: false } });
+}
+
+function handleClickEvent(params) {
+    if (params["nodes"].length == 1) {
+        handleNodeClickEvent(params["nodes"][0])
+    }
+}
+
+function handleNodeClickEvent(nodeId) {
+    // if nodeId is null, hide
+    if (nodeId == null) {
+        // Ensure slider is hidden
+        $("#bolt_slideout_inner").css("display", "none");
+        return;
+    }
+
+    // add new values
+    var nodeDetails = json[nodeId];
+    //console.log(nodeDetails);
+
+    // Prep the json slightly
+    nodeDetails[":id"] = nodeId;
+    nodeDetails[":inputs_length"] = nodeDetails[":inputs"].length;
+    nodeDetails[":stats_length"] = nodeDetails[":stats"].length;
+
+    // Conditionally link to component
+    for (x=0; x<nodeDetails[":inputs"].length; x++) {
+        var showLink = true;
+        if (nodeDetails[":inputs"][x][":component"].startsWith("__")) {
+            showLink = false;
+        }
+        nodeDetails[":inputs"][x][":show_link"] = showLink;
+    }
+
+    // Calculate uptime in a nice format.
+    for (x=0; x<nodeDetails[":stats"].length; x++) {
+        nodeDetails[":stats"][x][":uptime_str"] = secondsToString(nodeDetails[":stats"][x][":uptime_secs"]);
+    }
+
+    // Render and display template.
+    var template = $('#bolt_info_template').html();
+    var html = Mustache.to_html(template, nodeDetails);
+    $("#bolt-details").html(html);
+
+    // Ensure slider is viewable
+    $("#bolt_slideout_inner").css("display", "inline");
+    return;
+}
+
+function parseNode(nodeJson, nodeId) {
+    // Conditional hack for system components
+    if (isSystemComponent(nodeId)) {
+        nodeJson[":type"] = "system";
+    }
+
+    // Determine node color
+    var col = "#D2E5FF"
+    var selectedCol = "#97C2FC";
+    var shape = "dot"
+
+    if (nodeJson[":type"] === "bolt") {
+        // Determine color based on capacity
+        var cap = Math.min(nodeJson[":capacity"], 1);
+        var red = Math.floor(cap * 225) + 30;
+        var green = Math.floor(255 - red);
+        var blue = Math.floor(green/5);
+        col = "rgba(" + red + "," + green + "," + blue + ",1)"
+        selectedCol = "rgba(" + (red+2) + "," + (green) + "," + (green + 2) + ",1)"
+    }
+    if (nodeJson[":type"] === "spout") {
+        shape = "triangleDown";
+        col = "#D2E5FF";
+        selectedCol = "#97C2FC"
+    }
+    if (nodeJson[":type"] === "system") {
+        shape = "diamond";
+        col = "#ffe6cc";
+        selectedCol = "#ffc180";
+    }
+
+    // Generate title
+    var title = "<b>" + nodeId + "</b><br/>";
+    title += "Capacity: " + nodeJson[":capacity"] + "<br/>";
+    title += "Latency: " + nodeJson[":latency"]
+
+    // Construct the node
+    var node = {
+        "id": nodeId,
+        "label": nodeId,
+        "color": {
+            "background": col,
+            "highlight": {
+                "background": selectedCol
+            }
+        },
+        "shape": shape,
+        "shadow": {
+            "enabled": true
+        },
+        "title": title,
+        "size": 45
+    };
+
+    // Construct edges
+    for (var index in nodeJson[":inputs"]) {
+        var inputComponent = nodeJson[":inputs"][index];
+        parseEdge(inputComponent, nodeId);
+    }
+
+    if (node != null) {
+        visNS.nodes.update(node);
+    }
+}
+
+function isSystemComponent(nodeId) {
+    return nodeId.startsWith("__");
+}
+
+function parseEdge(edgeJson, sourceId) {
+    //console.log(edgeJson);
+
+    // Make this stream available
+    addAvailableStream(edgeJson[":stream"], edgeJson[":sani-stream"])
+
+    // Create a unique Id
+    var id = edgeJson[":component"] + ":" + sourceId + ":" + edgeJson[":sani-stream"];
+
+    // Determine if stream is enabled
+    if (!isStreamEnabled(edgeJson[":sani-stream"])) {
+        // Remove edge
+        visNS.edges.remove({ "id": id });
+        return
+    }
+
+    if (!visNS.edges.get(id)) {
+        visNS.edges.update({
+            "id": id,
+            "from": edgeJson[":component"],
+            "to": sourceId,
+            "label": edgeJson[":stream"],
+            "title": "From: " + edgeJson[":component"] + "<br>To: " + sourceId + "<br>Grouping: " + edgeJson[":grouping"]
+        });
+    }
+}
+
+function addAvailableStream(streamId, streamIdSanitized) {
+    // Create a master list of all streams
+    if (visNS.availableStreamsHash[streamIdSanitized] == null) {
+        visNS.availableStreamsHash[streamIdSanitized] = streamId;
+        updateAvailableStreams();
+    }
+}
+
+function updateAvailableStreams() {
+    var container = jQuery("#available-streams");
+    $.each(visNS.availableStreamsHash, function(streamIdSanitized, streamName) {
+        var entry = jQuery(container).find("#stream-" + streamIdSanitized)
+        if (entry.length == 0) {
+            var checked = "checked"
+            if (streamName.startsWith("__")) {
+                checked = ""
+            }
+            // Render template
+            var template = $('#stream_selector_template').html();
+            var html = Mustache.to_html(template, {"checked": checked, "streamName": streamName, "streamNameSanitized": streamIdSanitized});
+            container.append(html);
+
+            // keep list of streams in sorted order
+            jQuery("#available-streams li").sort(asc_sort).appendTo('#available-streams');
+        }
+    });
+}
+
+// Called when a stream's checkbox is selected/unselected.
+function checkStream(checkBox) {
+    // reload data
+    parseResponse(json);
+}
+
+// Redraws edges
+function redrawStreams() {
+    visNS.edges.forEach(function(edge) { visNS.edges.remove(edge); visNS.edges.add(edge); });
+}
+
+// Returns true if a stream is enabled
+function isStreamEnabled(streamIdSanitized) {
+    return jQuery("input#stream-" + streamIdSanitized).is(':checked')
+}
+
+var update = function() {
+    if(visNS.shouldUpdate) {
+        $.ajax({
+            url: "/api/v1/topology/"+$.url("?id")+"/visualization?sys="+$.url("?sys"),
+            success: function (data, status, jqXHR) {
+                json = data;
+                parseResponse(data);
+                setTimeout(update, visNS.updateFreqMs);
+            }
+        });
+    } else {
+        setTimeout(update, visNS.updateFreqMs);
+    }
+}
+
+function secondsToString(seconds) {
+    var numDays = Math.floor(seconds / 86400);
+    var numHours = Math.floor((seconds % 86400) / 3600);
+    var numMinutes = Math.floor(((seconds % 86400) % 3600) / 60);
+    var numSeconds = ((seconds % 86400) % 3600) % 60;
+
+    var returnStr = "";
+    if (numDays > 0) {
+        returnStr += numDays + " days ";
+    }
+    if (numHours > 0) {
+        returnStr += numHours + " hours ";
+    }
+    if (numMinutes > 0) {
+        returnStr += numMinutes + " mins ";
+    }
+    if (numSeconds > 0) {
+        returnStr += numSeconds + " seconds";
+    }
+    return returnStr;
+}
+
+// ascending sort
+function asc_sort(a, b){
+    return ($(b).text()) < ($(a).text()) ? 1 : -1;
+}
+
+$(document).ready(function() {
+    visNS.networkContainer = document.getElementById("mynetwork");
+    update();
+});
+

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer.html
new file mode 100644
index 0000000..fb60781
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer.html
@@ -0,0 +1,27 @@
+
+<html><head>
+    <!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+     contributor license agreements.  See the NOTICE file distributed with
+     this work for additional information regarding copyright ownership.
+     The ASF licenses this file to You 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.
+    -->
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Storm Logviewer</title>
+</head>
+<body>
+<p>You have launched storm logviewer successfully. You can visit logs from Storm UI now.</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer_search.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer_search.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer_search.html
new file mode 100644
index 0000000..5fb8870
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/logviewer_search.html
@@ -0,0 +1,72 @@
+<html><head>
+    <!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+     contributor license agreements.  See the NOTICE file distributed with
+     this work for additional information regarding copyright ownership.
+     The ASF licenses this file to You 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.
+    -->
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Storm UI</title>
+<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css">
+<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css">
+<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css?_ts=${packageTimestamp}" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.dataTables.1.10.4.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/bootstrap-3.3.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script>
+<script src="/js/url.min.js" type="text/javascript"></script>
+<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
+<script src="/js/script.js?_ts=${packageTimestamp}" type="text/javascript"></script>
+</head>
+<body>
+<div class="container-fluid">
+  <div class="row">
+    <div id="search-form"></div>
+  </div>
+  <div class="row">
+    <div id="result"></div>
+  </div>
+  <div>
+    <p id="page-rendered-at-timestamp"></p>
+  </div>
+</div>
+</body>
+<script>
+$(document).ready(function() {
+    var file = $.url("?file");
+    var search = $.url("?search");
+    var offset = $.url("?offset") || 0;
+    var isDaemon = $.url("?is-daemon") || "no";
+    file = decodeURIComponent(file);
+    search = decodeURIComponent(search);
+
+    getStatic("/templates/logviewer-search-page-template.html", function(template) {
+        $("#search-form").append(Mustache.render($(template).filter("#search-single-file").html(),{file: file, search: search, isDaemon: isDaemon}));
+
+        var result = $("#result");
+        var url = "/api/v1/search?file="+encodeURIComponent(file)+"&search-string="+search+"&start-byte-offset="+offset+"&is-daemon="+isDaemon;
+        $.getJSON(url,function(response,status,jqXHR) {
+           response.file = file;
+           result.append(Mustache.render($(template).filter("#logviewer-search-result-template").html(),response));
+       });
+    });
+  });
+
+getPageRenderedTimestamp("page-rendered-at-timestamp");
+
+</script>
+</html>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/owner.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/owner.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/owner.html
new file mode 100644
index 0000000..1e8bd5f
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/owner.html
@@ -0,0 +1,211 @@
+<html>
+
+<head>
+    <!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+     contributor license agreements.  See the NOTICE file distributed with
+     this work for additional information regarding copyright ownership.
+     The ASF licenses this file to You 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.
+    -->
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Storm UI</title>
+    <link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css">
+    <link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css">
+    <link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css">
+    <link href="/css/jsonFormatter.min.css" rel="stylesheet" type="text/css">
+    <link href="/css/style.css?_ts=${packageTimestamp}" rel="stylesheet" type="text/css">
+    <script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script>
+    <script src="/js/jquery.dataTables.1.10.4.min.js" type="text/javascript"></script>
+    <script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+    <script src="/js/jquery.mustache.js" type="text/javascript"></script>
+    <script src="/js/url.min.js" type="text/javascript"></script>
+    <script src="/js/bootstrap-3.3.1.min.js" type="text/javascript"></script>
+    <script src="/js/jquery.blockUI.min.js" type="text/javascript"></script>
+    <script src="/js/jsonFormatter.min.js" type="text/javascript"></script>
+    <script src="/js/script.js?_ts=${packageTimestamp}" type="text/javascript"></script>
+</head>
+
+<body>
+  <div class="warning" id="ras-warning-fixed-buffer">
+    <H1>This user's topologies are in danger of being unscheduled due to the owner's over-use of cluster resources.</H1>
+    <p>Please keep this user's resource consumption within guaranteed bounds to ensure topologies for this user will continue to run.</p>
+  </div>
+  <div class="warning" id="ras-warning-top-buffer"></div>
+  <div class="container-fluid">
+    <div class="row">
+        <div class="col-md-11">
+            <h1><a href="/">Storm UI</a></h1>
+        </div>
+        <div id="ui-user" class="col-md-1"></div>
+    </div>
+    <div class="row">
+        <div class="col-md-12" id="search-form">
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-12">
+            <h2>Owner Summary</h2>
+            <div id="owner-summary"></div>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-12">
+            <h2 id="owner-resource-usage-summary-header">Owner Resource Usage</h2>
+            <div id="owner-resource-usage-summary"></div>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-12">
+            <h2 id="owner-resource-guarantee-summary-header">Owner Resource Guarantees (RAS Topologies Only)</h2>
+            <div id="owner-resource-guarantee-summary"></div>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-12">
+            <h2>Owner Topologies</h2>
+            <div id="topology-summary"></div>
+        </div>
+    </div>
+    <div class="row">
+        <div id="json-response-error" class="col-md-12"></div>
+    </div>
+    <div>
+        <p id="page-rendered-at-timestamp"></p>
+    </div>
+</div>
+</body>
+<script>
+    $(document).ajaxStop($.unblockUI);
+    $(document).ajaxStart(function() {
+        $.blockUI({
+            message: '<img src="images/spinner.gif" /> <h3>Loading summary...</h3>'
+        });
+    });
+    $(document).ready(function() {
+
+        var owner = $.url("?id");
+        if (!owner) {
+            // this page is designed to be per owner, handle the case where the URL is malformed
+            getStatic("/templates/json-error-template.html", function(template) {
+                $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(), {
+                    "error": "Invalid owner",
+                    "errorMessage": "Please pass an owner id with the id URL parameter"
+                }));
+            });
+            return;
+        }
+        var url = "/api/v1/owner-resources/" + owner;
+
+        $.extend($.fn.dataTable.defaults, {
+            stateSave: true,
+            lengthMenu: [
+                [20, 40, 60, 100, -1],
+                [20, 40, 60, 100, "All"]
+            ],
+            pageLength: 20
+        });
+
+        $.ajaxSetup({
+            "error": function(jqXHR, textStatus, response) {
+                var errorJson = jQuery.parseJSON(jqXHR.responseText);
+                getStatic("/templates/json-error-template.html", function(template) {
+                    $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(), errorJson));
+                });
+            }
+        });
+
+        function jsError(other) {
+            try {
+                other();
+            } catch (err) {
+                getStatic("/templates/json-error-template.html", function(template) {
+                    $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(), {
+                        error: "JS Error",
+                        errorMessage: err
+                    }));
+                });
+            }
+        }
+
+        var topologySummary = $("#topology-summary");
+        var ownerResourceUsage = $("#owner-resource-usage-summary");
+        var ownerSummary = $("#owner-summary");
+        var ownerResourceGuarantee = $("#owner-resource-guarantee-summary");
+        $.getJSON(url, function(response, status, jqXHR) {
+            getStatic("/templates/owner-page-template.html", function(template) {
+                jsError(function() {
+                    //owner,totalTopologies,totalTasks,totalExecutors,totalWorkers
+                    ownerSummary.append(
+                        Mustache.render($(template).filter("#owner-summary-template").html(), response));
+
+                    //totalReqOnHeapMem,totalReqOffHeapMem,totalReqMem,totalReqCpu,totalAssignedOnHeapMem,totalAssignedOffHeapMem,totalAssignedMem,totalAssignedCpu
+                    ownerResourceUsage.append(
+                        Mustache.render($(template).filter("#owner-resource-usage-template").html(), response));
+                    $('#owner-resource-usage-summary [data-toggle="tooltip"]').tooltip();
+
+                    if (response["cpuGuarantee"] != "N/A" || response["memoryGuarantee"] != "N/A") {
+                        ownerResourceGuarantee.append(
+                            Mustache.render($(template).filter("#owner-resource-guarantee-template").html(), response));
+                        $('#owner-resource-guarantee-summary [data-toggle="tooltip"]').tooltip();
+
+                        $('#mem-guarantee-util').html(getResourceGuaranteeRemainingFormat("display", response["memoryGuaranteeRemaining"]));
+
+                        $('#cpu-guarantee-util').html(getResourceGuaranteeRemainingFormat("display", response["cpuGuaranteeRemaining"]));
+
+                    } else {
+                        $('#owner-resource-guarantee-summary-header').hide();
+                        $('#owner-resource-guarantee-summary').hide();
+                    }
+
+                    var displayResource = response["schedulerDisplayResource"];
+                    if (!displayResource) {
+                        $('#owner-resource-usage-summary-header').hide();
+                        $('#owner-resource-usage-summary').hide();
+                        $('#owner-resource-guarantee-summary-header').hide();
+                        $('#owner-resource-guarantee-summary').hide();
+                    }
+
+                    if(response && (response["memoryGuaranteeRemaining"] < 0 || response["cpuGuaranteeRemaining"] < 0
+                        || response["memoryGuaranteeRemaining"] == "N/A" || response["cpuGuaranteeRemaining"] == "N/A")) {
+                        $(".warning").show();
+                    } else {
+                        $(".warning").hide();
+                    }
+
+                    $('#owner-resource-usage-summary [data-toggle="tooltip"]').tooltip();
+
+                    topologySummary.append(
+                        Mustache.render($(template).filter("#owner-topology-summary-template").html(), response));
+                    //name, owner, status, uptime, num workers, num executors, num tasks, assigned total mem, assigned total cpu, scheduler info
+                    dtAutoPage("#owner-topology-summary-table", {
+                        columnDefs: [{
+                            type: "num",
+                            targets: [4, 5, 6, 7, 8]
+                        }, {
+                            type: "time-str",
+                            targets: [3]
+                        }]
+                    });
+                    $('#topology-summary [data-toggle="tooltip"]').tooltip();
+
+                });
+            });
+        });
+    });
+
+    getPageRenderedTimestamp("page-rendered-at-timestamp");
+
+</script>
+
+</html>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/search_result.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/search_result.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/search_result.html
new file mode 100644
index 0000000..30f09e4
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/search_result.html
@@ -0,0 +1,108 @@
+<html><head>
+    <!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+     contributor license agreements.  See the NOTICE file distributed with
+     this work for additional information regarding copyright ownership.
+     The ASF licenses this file to You 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.
+    -->
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Storm UI</title>
+<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css">
+<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css">
+<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css?_ts=${packageTimestamp}" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.dataTables.1.10.4.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/bootstrap-3.3.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script>
+<script src="/js/url.min.js" type="text/javascript"></script>
+<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
+<script src="/js/script.js?_ts=${packageTimestamp}" type="text/javascript"></script>
+</head>
+<body>
+<div class="container-fluid">
+  <div class="row">
+    <div id="search-form"></div>
+  </div>
+  <div class="row">
+    <div id="result"></div>
+  </div>
+  <div>
+    <p id="page-rendered-at-timestamp"></p>
+  </div>
+</div>
+</body>
+<script>
+$(document).ready(function() {
+    var id = $.url("?id");
+    var search = $.url("?search");
+    var count = $.url("?count") || 2;
+    var searchArchived = $.url("?searchArchived") || "";
+
+    getStatic("/templates/search-result-page-template.html", function(template) {
+        $("#search-form").append(Mustache.render($(template).filter("#search-form-template").html(),{id: id, search: search, count: count, searchArchived: searchArchived}));
+
+        var result = $("#result");
+        $.getJSON("/api/v1/topology-workers/"+id, function(response,status,jqXHR) {
+           for (var index in response.hostPortList) {
+             var host = response.hostPortList[index].host;
+             var port = response.hostPortList[index].port;
+             var elemId = "search-results-"+host.replace(/\./g,"-")+"-"+port;
+             response.hostPortList[index].elemId = elemId;
+           }
+           result.append(Mustache.render($(template).filter("#search-result-files-template").html(),response));
+
+           var logviewerPort = response.logviewerPort;
+           var logviewerScheme = response.logviewerScheme;
+           for (var index in response.hostPortList) {
+             var host = response.hostPortList[index].host;
+             var port = response.hostPortList[index].port;
+             var elemId = response.hostPortList[index].elemId;
+             var file = id+"/"+port+"/worker.log";
+             var searchURL = logviewerScheme + "://"+host+":"+logviewerPort+"/api/v1/search?file="+encodeURIComponent(file)+"&search-string="+search+"&num-matches="+count;
+             if (searchArchived != "") {
+               searchURL = logviewerScheme + "://"+host+":"+logviewerPort+"/api/v1/deepSearch/"+id+"?search-string="+search+"&num-matches="+count+"&search-archived=true&port="+port;
+             }
+
+             $.ajax({dataType: "json",
+               url: searchURL,
+               xhrFields: {
+                 withCredentials: true
+               },
+               success: $.proxy(function(data,status,jqXHR) {
+                                  data.file = this.file;
+                                  data.host = this.host;
+                                  data.port = this.port;
+                                  data.id = id;
+                                  data.logviewerPort = logviewerPort;
+                                  data.logviewerScheme = logviewerScheme;
+                                  var searchTemp = $(template).filter("#search-result-identified-template").html();
+                                  if (searchArchived != "") {
+                                    searchTemp = $(template).filter("#deepsearch-result-identified-template").html();
+                                  }
+                                  var rendered = Mustache.render(searchTemp, data);
+                                  $("#"+this.elemId).replaceWith(rendered);
+                                  }, {host: host, port: port, file: file, elemId: elemId})
+             });
+           }
+       });
+    });
+  });
+
+  getPageRenderedTimestamp("page-rendered-at-timestamp");
+
+</script>
+</html>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/supervisor.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/supervisor.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/supervisor.html
new file mode 100644
index 0000000..5489d5a
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/supervisor.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+
+<html><head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Storm UI</title>
+<link href="/css/bootstrap-3.3.1.min.css" rel="stylesheet" type="text/css">
+<link href="/css/jquery.dataTables.1.10.4.min.css" rel="stylesheet" type="text/css">
+<link href="/css/dataTables.bootstrap.css" rel="stylesheet" type="text/css">
+<link href="/css/jsonFormatter.min.css" rel="stylesheet" type="text/css">
+<link href="/css/style.css?_ts=${packageTimestamp}" rel="stylesheet" type="text/css">
+<script src="/js/jquery-1.11.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.dataTables.1.10.4.min.js" type="text/javascript"></script>
+<script src="/js/jquery.cookies.2.2.0.min.js" type="text/javascript"></script>
+<script src="/js/jquery.mustache.js" type="text/javascript"></script>
+<script src="/js/url.min.js" type="text/javascript"></script>
+<script src="/js/bootstrap-3.3.1.min.js" type="text/javascript"></script>
+<script src="/js/jquery.blockUI.min.js" type="text/javascript"></script>
+<script src="/js/jsonFormatter.min.js" type="text/javascript"></script>
+<script src="/js/script.js?_ts=${packageTimestamp}" type="text/javascript"></script>
+<script src="/js/dataTables.bootstrap.min.js" type="text/javascript"></script>
+</head>
+<body>
+<div class="supervisor-page container-fluid">
+  <div class="row">
+    <div class="col-md-11">
+      <h1><a href="/">Storm UI</a></h1>
+    </div>
+    <div id="ui-user" class="col-md-1"></div>
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      <h2>Supervisor summary</h2>
+      <div id="supervisor-summary"></div>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      <h2 id="worker-resources-header">Worker resources</h2>
+      <div id="worker-resources"></div>
+    </div>
+  </div>
+  <div class="row">
+    <div class="col-md-12">
+      <span id="toggle-sys" style="display: block;" class="js-only"></span>
+    </div>
+  </div>
+  <div>
+    <p id="page-rendered-at-timestamp"></p>
+  </div>
+</div>
+</body>
+
+<script>
+    
+$(document).ajaxStop($.unblockUI);
+$(document).ajaxStart(function(){
+    $.blockUI({ message: '<img src="images/spinner.gif" /> <h3>Loading summary...</h3>'});
+});
+$(document).ready(function() {
+    var supervisorId = $.url("?id");
+    var host = $.url("?host");
+    var windowParam = $.url("?window");
+    var sys = $.cookies.get("sys") || "false";
+    var url = "/api/v1/supervisor?" + 
+                (supervisorId ? "id="+supervisorId : "host="+host) 
+                + "&sys="+sys;
+    if(windowParam) url += "&window=" + windowParam;
+    $.extend( $.fn.dataTable.defaults, {
+      stateSave: true,
+      lengthMenu: [[20,40,60,100,-1], [20, 40, 60, 100, "All"]],
+      pageLength: 20
+    });
+
+    renderToggleSys($("#toggle-sys"));
+
+    var supervisorSummary = $("#supervisor-summary");
+    var workerStats = $("#worker-resources");
+
+    $.ajaxSetup({
+        "error":function(jqXHR,textStatus,response) {
+            var errorJson = jQuery.parseJSON(jqXHR.responseText);
+            getStatic("/templates/json-error-template.html", function(template) {
+                $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(),errorJson));
+            });
+        }
+    });
+    function jsError(other) {
+      try {
+        other();
+      } catch (err) {
+        getStatic("/templates/json-error-template.html", function(template) {
+          $("#json-response-error").append(Mustache.render($(template).filter("#json-error-template").html(),{error: "JS Error", errorMessage: err}));
+        });
+      }
+    }
+
+    $.getJSON(url,function(response,status,jqXHR) {
+        getStatic("/templates/supervisor-page-template.html", function(template) {
+            jsError(function() {
+                supervisorSummary.append(
+                        Mustache.render($(template).filter("#supervisor-summary-template").html(),response));
+                
+                //id, host, uptime, slots, used slots
+                dtAutoPage("#supervisor-summary-table", {
+                    columnDefs: [
+                    {type: "num", targets: [3, 4]},
+                    {type: "time-str", targets: [2]}
+                    ]
+                });
+
+                $('#supervisor-summary-table [data-toggle="tooltip"]').tooltip();
+                workerStats.append(Mustache.render($(template).filter("#worker-stats-template").html(),response));
+                makeSupervisorWorkerStatsTable(response, '#worker-stats-table', '#worker-resources');
+            });
+        });
+    });
+});
+
+getPageRenderedTimestamp("page-rendered-at-timestamp");
+
+</script>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/component-page-template.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/component-page-template.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/component-page-template.html
new file mode 100644
index 0000000..c1f3a19
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/component-page-template.html
@@ -0,0 +1,591 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<script id="component-summary-template" type="text/html">
+  <h2>Component summary</h2>
+  <table class="table compact">
+    <thead>
+      <tr>
+        <th>
+          <span data-toggle="tooltip" data-placement="right" title="The ID assigned to a the Component by the Topology.">
+            Id
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="The name given to the topology by when it was submitted. Click the name to view the Topology's information.">
+            Topology
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Executors are threads in a Worker process.">
+            Executors
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">
+            Tasks
+          </span>
+        </th>
+        {{#schedulerDisplayResource}}
+        <th>
+          <span data-toggle="tooltip" data-placement="above" title="The amount on heap memory in megabytes requested to run a single executor of this component.">
+            Requested On-heap Memory
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="above" title="The amount off heap memory in megabytes requested to run a single executor of this component.">
+            Requested Off-heap Memory
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="above" title="The amount of CPU resources requested to run a single executor of this component. Every 100 means 1 core.">
+            Requested CPU
+          </span>
+        </th>
+        {{/schedulerDisplayResource}}
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Click on the link below to open the logviewer and view the events emitted by this component.">
+            Debug
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr>
+        <td>{{id}}</td>
+        <td><a href="/topology.html?id={{encodedTopologyId}}">{{name}}</a></td>
+        <td>{{executors}}</td>
+        <td>{{tasks}}</td>
+        {{#schedulerDisplayResource}}
+        <td>{{requestedMemOnHeap}}</td>
+        <td>{{requestedMemOffHeap}}</td>
+        <td>{{requestedCpu}}</td>
+        {{/schedulerDisplayResource}}
+        <td><a href="{{eventLogLink}}">events</a></td>
+    </tbody>
+  </table>
+</script>
+<script id="spout-stats-detail-template" type="text/html">
+  <h2>Spout stats</h2>
+  <table class="table table-striped compact" id="spout-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The past period of time for which the statistics apply. Click on a value to set the window for this page.">
+            Window
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted.">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuples emitted that sent to one or more bolts." data-toggle="tooltip" data-placement="top">
+            Transferred
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The average time a Tuple &quot;tree&quot; takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">
+            Complete latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuple &quot;trees&quot; successfully processed. A value of 0 is expected if no acking is done.">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuple &quot;trees&quot; that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#spoutSummary}}
+      <tr>
+        <td><a href="/component.html?id={{encodedId}}&topology_id={{encodedTopologyId}}&window={{window}}">{{windowPretty}}</a></td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+        <td>{{completeLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/spoutSummary}}
+    </tbody>
+  </table>
+</script>
+<script id="output-stats-template" type="text/html">
+  <h2>Output stats ({{windowHint}})</h2>
+  <table class="table table-striped compact" id="output-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-original-title="The name of the Tuple stream given in the Topolgy, or &quot;default&quot; if none was given." data-toggle="tooltip" data-placement="right">
+            Stream
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted.">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuples emitted that sent to one or more bolts." data-toggle="tooltip" data-placement="top">
+            Transferred
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time a Tuple &quot;tree&quot; takes to be completely processed by the Topology. A value of 0 is expected if no acking is done." data-toggle="tooltip" data-placement="top">
+            Complete latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuple &quot;trees&quot; successfully processed. A value of 0 is expected if no acking is done." data-toggle="tooltip" data-placement="top">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuple &quot;trees&quot; that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#outputStats}}
+      <tr>
+        <td>{{stream}}</td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+        <td>{{completeLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/outputStats}}
+    </tbody>
+  </table>
+</script>
+<script id="executor-stats-template" type="text/html">
+  <h2>Executors ({{windowHint}})</h2>
+  <table class="table table-striped compact" id="executor-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The unique executor ID.">
+            Id
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="right" title="The length of time an Executor (thread) has been alive.">
+            Uptime
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">
+            Host
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The port number used by the Worker to which an Executor is assigned. Click on the port number to open the logviewer page for this Worker." data-toggle="tooltip" data-placement="top">
+            Port
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="Select workers on which to perform actions. Selecting any row will automatically select all executors belonging to the same worker." data-toggle="tooltip" data-placement="top">
+            Actions
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuples emitted." data-toggle="tooltip" data-placement="top">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted that sent to one or more bolts.">
+            Transferred
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The average time a Tuple &quot;tree&quot; takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.">
+            Complete latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuple &quot;trees&quot; successfully processed. A value of 0 is expected if no acking is done.">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuple &quot;trees&quot; that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#executorStats}}
+      <tr>
+        <td>{{id}}</td>
+        <td>{{uptime}}</td>
+        <td>{{host}}</td>
+        <td><a href="{{workerLogLink}}">{{port}}</a></td>
+        <td></td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+        <td>{{completeLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/executorStats}}
+    </tbody>
+  </table>
+</script>
+<script id="profiling-template" type="text/html">
+  <h2>Profiling and Debugging</h2>
+  Use the following controls to profile and debug the components on this page.
+  <table class="table table-striped compact">
+    <thead>
+      <tr>
+        <th class="header">
+          <span data-original-title="The status of a running profiler or the timeout for one you're starting (in minutes)" data-toggle="tooltip">
+            Status / Timeout (Minutes)
+          </span>
+        </th>
+        <th class="header">Actions</th>
+      </tr>
+    </thead>
+    <tbody id="profiler-table-body">
+      <tr>
+        <td>
+          <input id="timeout" class="timeout_input" type="text" value="" placeholder="10"/>
+        </td>
+        <td>
+          <span id="workerActionButtons">
+            {{#profileActionEnabled}}
+            <input type="button" value="Start" name="start" onClick="start_profiling()" class="btn btn-secondary" disabled/>
+            {{/profileActionEnabled}}
+            <input type="button" value="JStack" name="jstack" onClick="dump_jstacks()" class="btn btn-secondary" disabled/>
+            <input type="button" value="Restart Worker" name="jvmrestart" onClick="restart_worker_jvms()" class="btn btn-secondary" disabled/>
+            <input type="button" value="Heap" name="heap" onClick="dump_heaps()" class="btn btn-secondary" disabled/>
+          </span>
+        </td>
+      </tr>
+      {{> profilerActive}}
+    </tbody>
+  </table>
+</script>
+<script id="profiler-active-partial" type="text/html">
+  {{#profilerActive}}
+  <tr>
+    <td>{{host}}:{{port}}<br/>Active until {{timestamp}}</td>
+    <td>
+      <input id="stop_{{host}}:{{port}}" type="button" value="Stop" name="stop" onClick="stop_profiling('{{host}}:{{port}}')" class="btn btn-secondary"/>
+      <input id="dump_profile_{{host}}:{{port}}" type="button" value="Dump Profile" name="dumpjprofile" onClick="dump_profile('{{host}}:{{port}}')" class="btn btn-secondary"/>
+      <input id="dump_jstack_{{host}}:{{port}}" type="button" value="JStack" name="jstack" onClick="dump_jstack('{{host}}:{{port}}')" class="btn btn-secondary"/>
+      <input id="restart_worker_jvm_{{host}}:{{port}}" type="button" value="Restart Worker" name="jvmrestart" onClick="restart_worker_jvms(['{{host}}:{{port}}'])" class="btn btn-secondary"/>
+      <input id="dump_heap_{{host}}:{{port}}" type="button" value="Heap" name="heap" onClick="dump_heap('{{host}}:{{port}}')" class="btn btn-secondary"/> <a href="{{dumplink}}">My Dump Files</a>
+    </td>
+  </tr>
+  {{/profilerActive}}
+</script>
+<script id="bolt-stats-template" type="text/html">
+  <h2>Bolt stats</h2>
+  <table class="table table-striped compact" id="bolt-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The past period of time for which the statistics apply. Click on a value to set the window for this page.">
+            Window
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted.">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted that sent to one or more bolts.">
+            Transferred
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple." data-toggle="tooltip" data-placement="top">
+            Execute latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of incoming Tuples processed.">
+            Executed
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time it takes to Ack a Tuple after it is first received.  Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received." data-toggle="tooltip" data-placement="top">
+            Process latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuples acknowledged by this Bolt." data-toggle="tooltip" data-placement="top">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of tuples Failed by this Bolt." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#boltStats}}
+      <tr>
+        <td><a href="/component.html?id={{encodedId}}&topology_id={{encodedTopologyId}}&window={{window}}">{{windowPretty}}</a></td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+        <td>{{executeLatency}}</td>
+        <td>{{executed}}</td>
+        <td>{{processLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/boltStats}}
+    </tbody>
+  </table>
+</script>
+<script id="bolt-input-stats-template" type="text/html">
+  <h2>Input stats ({{windowHint}})</h2>
+  <table class="table table-striped compact" id="bolt-input-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The ID assigned to a the Component by the Topology.">
+            Component
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="right" title="The name of the Tuple stream given in the Topolgy, or &quot;default&quot; if none was given.">
+            Stream
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.">
+            Execute latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of incoming Tuples processed.">
+            Executed
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time it takes to Ack a Tuple after it is first received.  Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received." data-toggle="tooltip" data-placement="top">
+            Process latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples acknowledged by this Bolt.">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of tuples Failed by this Bolt." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#inputStats}}
+      <tr>
+        <td>{{component}}</td>
+        <td>{{stream}}</td>
+        <td>{{executeLatency}}</td>
+        <td>{{executed}}</td>
+        <td>{{processLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/inputStats}}
+    </tbody>
+  </table>
+</script>
+<script id="bolt-output-stats-template" type="text/html">
+  <h2>Output stats ({{windowHint}})</h2>
+  <table class="table table-striped compact" id="bolt-output-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The name of the Tuple stream given in the Topolgy, or &quot;default&quot; if none was given.">
+            Stream
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted.">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted that sent to one or more bolts.">
+            Transferred
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#outputStats}}
+      <tr>
+        <td>{{stream}}</td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+      </tr>
+      {{/outputStats}}
+    </tbody>
+  </table>
+</script>
+<script id="bolt-executor-template" type="text/html">
+  <h2>Executors ({{windowHint}})</h2>
+  <table class="table table-striped compact" id="executor-stats-table">
+    <thead>
+      <tr>
+        <th class="header headerSortDown">
+          <span data-toggle="tooltip" data-placement="right" title="The unique executor ID.">
+            Id
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The length of time an Executor (thread) has been alive." data-toggle="tooltip" data-placement="right">
+            Uptime
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">
+            Host
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The port number used by the Worker to which an Executor is assigned. Click on the port number to open the logviewer page for this Worker.">
+            Port
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="Select workers on which to perform actions. Selecting any row will automatically select all executors belonging to the same worker." data-toggle="tooltip" data-placement="top">
+            Debug
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted.">
+            Emitted
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of Tuples emitted that sent to one or more bolts.">
+            Transferred
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="If this is around 1.0, the corresponding Bolt is running as fast as it can, so you may want to increase the Bolt's parallelism. This is (number executed * average execute latency) / measurement time.">
+            Capacity (last 10m)
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple." data-toggle="tooltip" data-placement="top">
+            Execute latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-toggle="tooltip" data-placement="top" title="The number of incoming Tuples processed.">
+            Executed
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The average time it takes to Ack a Tuple after it is first received.  Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received." data-toggle="tooltip" data-placement="top">
+            Process latency (ms)
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of Tuples acknowledged by this Bolt." data-toggle="tooltip" data-placement="top">
+            Acked
+          </span>
+        </th>
+        <th class="header">
+          <span data-original-title="The number of tuples Failed by this Bolt." data-toggle="tooltip" data-placement="left">
+            Failed
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#executorStats}}
+      <tr>
+        <td>{{id}}</td>
+        <td>{{uptime}}</td>
+        <td>{{host}}</td>
+        <td><a href="{{workerLogLink}}">{{port}}</a></td>
+        <td></td>
+        <td>{{emitted}}</td>
+        <td>{{transferred}}</td>
+        <td>{{capacity}}</td>
+        <td>{{executeLatency}}</td>
+        <td>{{executed}}</td>
+        <td>{{processLatency}}</td>
+        <td>{{acked}}</td>
+        <td>{{failed}}</td>
+      </tr>
+      {{/executorStats}}
+    </tbody>
+  </table>
+</script>
+<script id="component-errors-template" type="text/html">
+  <h2>Errors</h2>
+  <table class="table table-striped compact" id="component-errors-table">
+    <thead>
+      <tr>
+        <th>Time</th>
+        <th>Error Host</th>
+        <th>Error Port</th>
+        <th>Error</th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#componentErrors}}
+      <tr>
+        <td>
+          <span id="{{errorTime}}" class="errorTimeSpan">{{errorTime}}</span>
+        </td>
+        <td>{{errorHost}}</td>
+        <td><a href="{{errorWorkerLogLink}}">{{errorPort}}</a></td>
+        <td>
+          <span id="{{errorLapsedSecs}}" class="errorSpan">{{error}}</span>
+        </td>
+      </tr>
+      {{/componentErrors}}
+    </tbody>
+  </table>
+</script>
+<script id="component-actions-template" type="text/html">
+  <h2>Component actions</h2>
+  <p id="component-actions">
+    {{#loggersDisabled}}
+    <span style="display:inline-block;" data-toggle="tooltip" title="" data-original-title="To debug, set topology.eventlogger.executors to a value > 0">
+    {{/loggersDisabled}}
+      <input {{startDebugStatus}} onclick="confirmComponentAction('{{encodedTopologyId}}', '{{encodedId}}', '{{componentName}}', 'debug/enable', true, {{currentSamplingPct}}, 'sampling percentage', 'debug')" type="button" value="Debug" class="btn btn-default">
+    {{#loggersDisabled}}
+    </span>
+    {{/loggersDisabled}}
+    <input {{stopDebugStatus}} onclick="confirmComponentAction('{{encodedTopologyId}}', '{{encodedId}}', '{{componentName}}', 'debug/disable', false, 0, 'sampling percentage', 'stop debugging')" type="button" value="Stop Debug" class="btn btn-default">
+  </p>
+</script>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/deep-search-result-page-template.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/deep-search-result-page-template.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/deep-search-result-page-template.html
new file mode 100644
index 0000000..e5146d8
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/deep-search-result-page-template.html
@@ -0,0 +1,72 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<script id="search-result-files-template" type="text/html">
+<table id="search-result-table" class="table table-striped compact">
+  <thead><tr><th>host:port</th><th>Match</th></tr></thead>
+  <tbody>
+    {{#supervisors}}
+    <tr id="{{elemId}}">
+      <td>{{host}}</td>
+      <td>LOADING ...</td>
+    </tr>
+    {{/supervisors}}
+  </tbody>
+</table>
+</script>
+<script id="search-result-identified-template" type="text/html">
+    {{#matches}}
+    <tr id="aResult">
+      <td><a href="{{logviewerScheme}}://{{host}}:{{logviewerPort}}/logviewer_search.html?file={{fileName}}&search={{searchString}}">{{host}}:{{port}}</a></td>
+      <td><pre>{{beforeString}}<b><a href="{{logviewerURL}}">{{matchString}}</a></b>{{afterString}}</pre></td>
+    </tr>
+    {{/matches}}
+    {{#resultNotFound}}
+    <tr id="noResult">
+      <td>Result Not Found</td>
+      <td></td>
+    </tr>
+    {{/resultNotFound}}
+</script>
+<script id="search-form-template" type="text/html">
+  <div id="search-form-container" class="search-box">
+    <form action="deep_search_result.html" id="search-box">
+      <div class="row"  data-toggle="tooltip" data-placement="bottom" title="The ID of the topology, can be a regex for search, i.e. '.' lists everything">
+        <div class="col-md-2">Topology Id:</div>
+        <div class="col-md-10">
+          <input class="expand-box" id="search-id" name="id" class="typeahead" type="text" placeholder="Topology-ID" value="{{id}}" number="50">
+        </div>
+      </div>
+      <div class="row" data-toggle="tooltip" data-placement="bottom" title="Exact search string to look for (NOT A REGEX)">
+        <div class="col-md-2">Search:</div>
+        <div class="col-md-10">
+          <input class="expand-box" type="text" name="search" value="{{search}}" placeholder="Search" number="50">
+        </div>
+      </div>
+      <div class="row" data-toggle="tooltip" data-placement="bottom" title="Search older logs that have rotated and may have been compressed.  This could take much longer.">
+        <div class="col-md-2">Search archived logs:</div>
+        <div class="col-md-10"><input type="checkbox" name="search-archived" {{search_archived}}></div>
+      </div>
+      <div class="row">
+        <div class="col-md-12">
+          <input type="submit" value="Search">
+        </td>
+      </div>
+      <input type="hidden" name="count" value="{{count}}">
+    </form>
+  </div>
+</script>
+

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/index-page-template.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/index-page-template.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/index-page-template.html
new file mode 100644
index 0000000..48658a9
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/index-page-template.html
@@ -0,0 +1,446 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<script id="cluster-summary-template" type="text/html">
+<table id="cluster-summary-table" class="table compact">
+  <thead>
+    <tr>
+      <th>
+        <span data-toggle="tooltip" data-placement="right" title="The version of storm installed on the UI node. (Hopefully, this is the same on all storm nodes!)">
+          Version
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The number of nodes in the cluster currently.">
+          Supervisors
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of Slots. Slots are Workers (processes).">
+          Used slots
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of Slots. Slots are Workers (processes).">
+          Free slots
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of Slots. Slots are Workers (processes).">
+          Total slots
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Executors are threads in a Worker process.">
+          Executors
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">
+          Tasks
+        </span>
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>{{stormVersion}}</td>
+      <td>{{supervisors}}</td>
+      <td>{{slotsUsed}}</td>
+      <td>{{slotsFree}}</td>
+      <td>{{slotsTotal}}</td>
+      <td>{{executorsTotal}}</td>
+      <td>{{tasksTotal}}</td>
+    </tr>
+  </tbody>
+</table>
+</script>
+
+<script id="nimbus-summary-template" type="text/html">
+    <table class="zebra-striped" id="nimbus-summary-table">
+        <thead>
+        <tr>
+            <th>
+                <span data-toggle="tooltip" data-placement="right" title="nimbus host name.">Host</span>
+            </th>
+            <th>
+                <span data-toggle="tooltip" data-placement="top" title="Nimbus Thrift port number.">Port</span>
+            </th>
+            <th>
+                <span data-toggle="tooltip" data-placement="top" title="Leader if this host is leader, Not a Leader for all other live hosts,
+                note that these hosts may or may not be in leader lock queue, and Dead for hosts that are part of nimbus.seeds list but are not alive.">Status</span>
+            </th>
+            <th>
+                <span data-toggle="tooltip" data-placement="top" title="Storm version this nimbus host is running.">Version</span>
+            </th>
+            <th>
+                <span data-toggle="tooltip" data-placement="left" title="Time since this nimbus host has been running.">Uptime</span>
+            </th>
+        </tr>
+        </thead>
+        <tbody>
+        {{#nimbuses}}
+        <tr>
+            <td>{{host}}</td>
+            <td><a href="{{nimbusLogLink}}">{{port}}</a></td>
+            <td>{{status}}</td>
+            <td>{{version}}</td>
+            <td>{{nimbusUpTime}}</td>
+        </tr>
+        {{/nimbuses}}
+        </tbody>
+    </table>
+</script>
+<script id="cluster-resources-template" type="text/html">
+    <table id="cluster-resources-table" class="table compact">
+      <thead>
+      <tr>
+        <th>
+            <span data-toggle="tooltip" data-placement="right" title="Total Available Memory in Cluster in MB.">
+              Total Memory (MB)
+            </span>
+        </th>
+        <th>
+            <span data-toggle="tooltip" data-placement="right" title="Total Available Memory in Cluster in MB.">
+              Total Available Memory (MB)
+            </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="right" title="Total Fragmented Memory in Cluster in MB.">
+            Total Fragmented Memory (MB)
+          </span>
+        </th>
+        <th>
+            <span data-toggle="tooltip" data-placement="top" title="Percent Utilization of Memory Resources in Cluster.">
+              Memory Utilization (%)
+            </span>
+        </th>
+        <th>
+            <span data-toggle="tooltip" data-placement="top" title="Total CPU Resources in Cluster. Every 100 means 1 core.">
+              Total CPU (%)
+            </span>
+        </th>
+        <th>
+            <span data-toggle="tooltip" data-placement="top" title="Total Available CPU Resources in Cluster. Every 100 means 1 core.">
+              Available CPU (%)
+            </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Total Fragmented CPU Resources in Cluster. Every 100 means 1 core.">
+            Fragmented CPU (%)
+          </span>
+        </th>
+        <th>
+            <span data-toggle="tooltip" data-placement="top" title="Percent Utilization of CPU Resources in Cluster.">
+             CPU Utilization (%)
+            </span>
+        </th>
+      </tr>
+      </thead>
+      <tbody>
+      <tr>
+        <td>{{totalMem}}</td>
+        <td>{{availMem}}</td>
+        <td>{{fragmentedMem}}</td>
+        <td>{{memAssignedPercentUtil}}</td>
+        <td>{{totalCpu}}</td>
+        <td>{{availCpu}}</td>
+        <td>{{fragmentedCpu}}</td>
+        <td>{{cpuAssignedPercentUtil}}</td>
+      </tr>
+      </tbody>
+    </table>
+</script>
+<script id="owner-summary-template" type="text/html">
+  <table class="table table-striped compact" id="owner-summary-table">
+    <thead>
+    <tr>
+      <th>
+        Owner
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of topologies owned by user.">
+          Total Topologies
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of executors used by user.">
+          Total Executors
+      </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of workers used by user.">
+          Total Workers
+      </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of memory resource (in MB) used by user.">
+          Memory Usage (MB)
+        </span>
+      </th>
+      {{#schedulerDisplayResource}}
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of memory resource (in MB) guaranteed to user.">
+            Memory Guarantee (MB)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of guaranteed memory resources (in MB) remaining.">
+          Memory Guarantee Remaining (MB)
+        </span>
+      </th>
+      <th>
+          <span data-toggle="tooltip" data-placement="top" title="Total CPU Resource Assigned on behalf of Owner. Every 100 means 1 core.">
+           CPU Usage (%)
+          </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of CPU resource (every 100 means 1 core) guaranteed to user.">
+            CPU Guarantee (%)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of guaranteed CPU resource (every 100 means 1 core) remaining.">
+          CPU Guarantee Remaining (%)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The amount of isolated nodes user may use">
+          Isolated Nodes Guarantee
+        </span>
+      </th>
+      {{/schedulerDisplayResource}}
+    </tr>
+    </thead>
+    <tbody>
+    </tbody>
+  </table>
+</script>
+<script id="topology-summary-template" type="text/html">
+  <table class="table table-striped compact" id="topology-summary-table">
+    <thead>
+      <tr>
+        <th>
+          <span data-toggle="tooltip" data-placement="right" title="The name given to the topology by when it was submitted. Click the name to view the Topology's information.">
+            Name
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="The user that submitted the Topology, if authentication is enabled.">
+            Owner
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="The status can be one of ACTIVE, INACTIVE, KILLED, or REBALANCING.">
+            Status
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="The time since the Topology was submitted.">
+            Uptime
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="The number of Workers (processes).">
+            Num workers
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Executors are threads in a Worker process.">
+            Num executors
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.">
+            Num tasks
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Number of nimbus hosts on which this topology's code is replicated. ">
+            Replication count
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Assigned Total Memory by Scheduler.">
+            Assigned Mem (MB)
+          </span>
+        </th>
+        {{#schedulerDisplayResource}}
+        <th>
+          <span data-toggle="tooltip" data-placement="top" title="Assigned Total CPU by Scheduler. Every 100 means 1 core.">
+            Assigned CPU (%)
+          </span>
+        </th>
+        {{/schedulerDisplayResource}}
+        <th>
+          <span data-toggle="tooltip" data-placement="left" title="This shows information from the scheduler about the latest attempt to schedule the Topology on the cluster.">
+            Scheduler Info
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="left" title="The version of this topology">
+            Topology Version
+          </span>
+        </th>
+        <th>
+          <span data-toggle="tooltip" data-placement="left" title="The version of the storm client that this topology request (was launched with)">
+            Storm Version
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      {{#topologies}}
+      <tr>
+        <td><a href="/topology.html?id={{encodedId}}">{{name}}</a></td>
+        <td><a href="/owner.html?id={{owner}}">{{owner}}</a></td>
+        <td>{{status}}</td>
+        <td>{{uptime}}</td>
+        <td>{{workersTotal}}</td>
+        <td>{{executorsTotal}}</td>
+        <td>{{tasksTotal}}</td>
+        <td>{{replicationCount}}</td>
+        <td>{{assignedTotalMem}}</td>
+        {{#schedulerDisplayResource}}
+        <td>{{assignedCpu}}</td>
+        {{/schedulerDisplayResource}}
+        <td>{{schedulerInfo}}</td>
+        <td>{{topologyVersion}}</td>
+        <td>{{stormVersion}}</td>
+      </tr>
+      {{/topologies}}
+    </tbody>
+  </table>
+</script>
+<script id="supervisor-summary-template" type="text/html">
+<table class="table table-striped compact" id="supervisor-summary-table">
+  <thead>
+    <tr>
+      <th>
+        <span data-toggle="tooltip" data-placement="right" title="The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.)">
+          Host
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="A unique identifier given to a Supervisor when it joins the cluster.">
+          Id
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The length of time a Supervisor has been registered to the cluster.">
+          Uptime
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="Total number of Slots. Slots are Workers (processes).">
+          Slots
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="Total number of Slots. Slots are Workers (processes).">
+          Used slots
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="The number of Slots available. Slots are Workers (processes).">
+          Avail slots
+        </span>
+      </th>
+      {{#schedulerDisplayResource}}
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The total memory capacity of a supervisor in megabytes.">
+          Total Mem (MB)
+        </span>
+      </th>
+      {{/schedulerDisplayResource}}
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="The amount of memory that has been allocated in megabytes.">
+          Used Mem (MB)
+        </span>
+      </th>
+      {{#schedulerDisplayResource}}
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="The amount of Memory available in megabytes.">
+          Avail Mem (MB)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="top" title="The total CPU capacity of a supervisor. Every 100 means one core.">
+          Total CPU (%)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="The amount of CPU that has been allocated. Every 100 means one core.">
+          Used CPU (%)
+        </span>
+      </th>
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="The amount of CPU that is available. Every 100 means one core.">
+          Avail CPU (%)
+        </span>
+      </th>
+      {{/schedulerDisplayResource}}
+      <th>
+        <span data-toggle="tooltip" data-placement="left" title="Version">
+          Version
+        </span>
+      </th>
+    </tr>
+  </thead>
+  <tbody>
+    {{#supervisors}}
+    <tr>
+      <td><a href="/supervisor.html?host={{host}}">{{host}}</a> (<a href="{{logLink}}" title="View log">log</a>)</td>
+      <td><a href="/supervisor.html?id={{id}}">{{id}}</a></td>
+      <td>{{uptime}}</td>
+      <td>{{slotsTotal}}</td>
+      <td>{{slotsUsed}}</td>
+      <td>{{slotsFree}}</td>
+      {{#schedulerDisplayResource}}
+      <td>{{totalMem}}</td>
+      {{/schedulerDisplayResource}}
+      <td>{{usedMem}}</td>
+      {{#schedulerDisplayResource}}
+      <td>{{availMem}}</td>
+      <td>{{totalCpu}}</td>
+      <td>{{usedCpu}}</td>
+      <td>{{availCpu}}</td>
+      {{/schedulerDisplayResource}}
+      <td>{{version}}</td>
+    </tr>
+    {{/supervisors}}
+  </tbody>
+</table>
+</script>
+
+<script id="configuration-template" type="text/html">
+  <table class="table table-striped compact" id="nimbus-configuration-table">
+    <thead>
+      <tr>
+        <th>Key</th>
+        <th>Value</th>
+    </tr>
+    </thead>
+    <tbody>
+      {{#config}}
+      <tr>
+        <td>{{key}}</td>
+        <td>{{value}}</td>
+      </tr>
+      {{/config}}
+    </tbody>
+  </table>
+</script>

http://git-wip-us.apache.org/repos/asf/storm/blob/034ac677/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/json-error-template.html
----------------------------------------------------------------------
diff --git a/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/json-error-template.html b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/json-error-template.html
new file mode 100644
index 0000000..f496cf8
--- /dev/null
+++ b/storm-webapp/src/main/java/org/apache/storm/daemon/ui/WEB-INF/templates/json-error-template.html
@@ -0,0 +1,20 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<script id="json-error-template" type="text/html">
+<h2>{{error}}</h2>
+<pre>{{errorMessage}}</pre>
+</script>