Repository: ambari Updated Branches: refs/heads/trunk 11ef5ca16 -> cd6398a1d
http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyGraphView.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyGraphView.js b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyGraphView.js new file mode 100644 index 0000000..01fccc9 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyGraphView.js @@ -0,0 +1,423 @@ +/** +* 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. +*/ + +define(['require', 'utils/Globals'], function(require, Globals) { + 'use strict' + + var topologyGraphView = Marionette.LayoutView.extend({ + template: _.template('<div><canvas id="topoGraph" width="844" height="260"></div>'), + + initialize: function(options) { + this.topologyId = options.id; + }, + onRender: function() { + var topology_data, + that = this; + var sys = arbor.ParticleSystem(20, 1000, 0.15, true, 55, 0.02, 0.6); + sys.renderer = this.renderGraph('#topoGraph'); + sys.stop(); + + Backbone.ajax({ + url: Globals.baseURL + "/api/v1/topology/" + this.topologyId + "/visualization", + success: function(data, status, jqXHR) { + if(_.isString(data)){ + data = JSON.parse(data); + } + topology_data = data; + that.update_data(topology_data, sys); + sys.renderer.signal_update(); + sys.renderer.redraw(); + that.rechoose(topology_data, sys, 'default') + } + }); + + }, + + renderGraph: function(elem) { + var canvas = this.$(elem).get(0); + var ctx = canvas.getContext("2d"); + var gfx = arbor.Graphics(canvas); + var psys; + + var totaltrans = 0; + var weights = {}; + var texts = {}; + var update = false; + var that = this; + var myRenderer = { + init: function(system) { + psys = system; + psys.screenSize(canvas.width, canvas.height) + psys.screenPadding(20); + myRenderer.initMouseHandling(); + }, + + signal_update: function() { + update = true; + }, + + redraw: function() { + if (!psys) + return; + + if (update) { + totaltrans = that.calculate_total_transmitted(psys); + weights = that.calculate_weights(psys, totaltrans); + texts = that.calculate_texts(psys, totaltrans); + update = false; + } + + + + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + var x = 0; + + + psys.eachEdge(function(edge, pt1, pt2) { + + var len = Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); + var sublen = len - (Math.max(50, 20 + gfx.textWidth(edge.target.name)) / 2); + var thirdlen = len / 3; + var theta = Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x); + + var newpt2 = { + x: pt1.x + (Math.cos(theta) * sublen), + y: pt1.y + (Math.sin(theta) * sublen) + }; + + var thirdpt = { + x: pt1.x + (Math.cos(theta) * thirdlen), + y: pt1.y + (Math.sin(theta) * thirdlen) + } + + var weight = weights[edge.source.name + edge.target.name]; + + if (!weights[edge.source.name + edge.target.name]) { + totaltrans = that.calculate_total_transmitted(psys); + weights = that.calculate_weights(psys, totaltrans); + } + + ctx.strokeStyle = "rgba(0,0,0, .333)"; + ctx.lineWidth = 25 * weight + 5; + ctx.beginPath(); + + var arrlen = 15; + ctx.moveTo(pt1.x, pt1.y); + ctx.lineTo(newpt2.x, newpt2.y); + ctx.lineTo(newpt2.x - arrlen * Math.cos(theta - Math.PI / 6), newpt2.y - arrlen * Math.sin(theta - Math.PI / 6)); + ctx.moveTo(newpt2.x, newpt2.y); + ctx.lineTo(newpt2.x - arrlen * Math.cos(theta + Math.PI / 6), newpt2.y - arrlen * Math.sin(theta + Math.PI / 6)); + + + if (texts[edge.source.name + edge.target.name] == null) { + totaltrans = calculate_total_transmitted(psys); + texts = calculate_texts(psys, totaltrans); + } + + gfx.text(texts[edge.source.name + edge.target.name], thirdpt.x, thirdpt.y + 10, { + color: "black", + align: "center", + font: "Arial", + size: 10 + }) + ctx.stroke(); + }); + + psys.eachNode(function(node, pt) { + var col; + + var real_trans = that.gather_stream_count(node.data[":stats"], "default", "600"); + + if (node.data[":type"] === "bolt") { + var cap = Math.min(node.data[":capacity"], 1); + var red = Math.floor(cap * 225) + 30; + var green = Math.floor(255 - red); + var blue = Math.floor(green / 5); + col = arbor.colors.encode({ + r: red, + g: green, + b: blue, + a: 1 + }); + } else { + col = "#0000FF"; + } + + var w = Math.max(55, 25 + gfx.textWidth(node.name)); + + gfx.oval(pt.x - w / 2, pt.y - w / 2, w, w, { + fill: col + }); + gfx.text(node.name, pt.x, pt.y + 3, { + color: "white", + align: "center", + font: "Arial", + size: 12 + }); + gfx.text(node.name, pt.x, pt.y + 3, { + color: "white", + align: "center", + font: "Arial", + size: 12 + }); + + gfx.text(_.isEqual(parseFloat(node.data[":latency"]).toFixed(2), 'NaN') ? "0.00 ms" : parseFloat(node.data[":latency"]).toFixed(2) + " ms", pt.x, pt.y + 17, { + color: "white", + align: "center", + font: "Arial", + size: 12 + }); + + }); + + // Draw heatmap + var rect_x = canvas.width - 250, + rect_y = canvas.height - 30, + colorArr = ['#ff0000', '#F7BF43', '#F4EA47', '#A4CC45', '#1EE12D']; + ctx.fillStyle = "grey"; + ctx.fillText("Heatmap", rect_x, rect_y - 5) + ctx.rect(rect_x, rect_y, 245, canvas.height - 50); + var grd = ctx.createLinearGradient(rect_x, rect_y, canvas.width - 5, rect_y); + grd.addColorStop(0.000, colorArr[0]); + grd.addColorStop(0.250, colorArr[1]); + grd.addColorStop(0.500, colorArr[2]); + grd.addColorStop(0.750, colorArr[3]); + grd.addColorStop(1.000, colorArr[4]); + ctx.fillStyle = grd; + ctx.fillRect(rect_x, rect_y, 245, canvas.height - 50); + + //Draw legends + var legendX = canvas.width - 140, + legendY = canvas.height - 170, + legendWidth = 30, + legendY1 = canvas.height - 240, + legendTextX = canvas.width - 105, + legendTextY = canvas.height - 160, + legendTextArr = ['0% - 20%', '21% - 40%', '41% - 60%', '61% - 80%', '81% - 100%']; + + for (var i = 0; i < colorArr.length; i++) { + ctx.rect(legendX, legendY + (i * 25), legendWidth, legendY1); + ctx.fillStyle = colorArr[4 - i]; + ctx.fillRect(legendX, legendY + (i * 25), legendWidth, legendY1); + ctx.fillStyle = "black"; + ctx.fillText(legendTextArr[i], legendTextX, legendTextY + (i * 25)); + } + + }, + + initMouseHandling: function() { + var dragged = null; + var clicked = false; + var _mouseP; + + var handler = { + clicked: function(e) { + var pos = $(canvas).offset(); + _mouseP = arbor.Point(e.pageX - pos.left, e.pageY - pos.top); + dragged = psys.nearest(_mouseP); + + if (dragged && dragged.node !== null) { + dragged.node.fixed = true; + } + + clicked = true; + setTimeout(function() { + clicked = false; + }, 50); + + $(canvas).bind('mousemove', handler.dragged); + $(window).bind('mouseup', handler.dropped); + + return false; + }, + + dragged: function(e) { + + var pos = $(canvas).offset(); + var s = arbor.Point(e.pageX - pos.left, e.pageY - pos.top); + + if (dragged && dragged.node != null) { + var p = psys.fromScreen(s); + dragged.node.p = p; + } + + return false; + + }, + + dropped: function(e) { + // if (clicked) { + // if (dragged.distance < 50) { + // if (dragged && dragged.node != null) { + // window.location = dragged.node.data[":link"]; + // } + // } + // } + + if (dragged === null || dragged.node === undefined) return; + if (dragged.node !== null) dragged.node.fixed = false; + dragged.node.tempMass = 1000; + dragged = null; + $(canvas).unbind('mousemove', handler.dragged); + $(window).unbind('mouseup', handler.dropped); + _mouseP = null; + return false; + } + + } + + $(canvas).mousedown(handler.clicked); + } + }; + + this.calculate_texts = function(psys, totaltrans) { + var texts = {}; + psys.eachEdge(function(edge, pt1, pt2) { + var text = ""; + for (var i = 0; i < edge.target.data[":inputs"].length; i++) { + var stream = edge.target.data[":inputs"][i][":stream"]; + var sani_stream = edge.target.data[":inputs"][i][":sani-stream"]; + if (edge.target.data[":inputs"][i][":component"] === edge.source.name) { + var stream_transfered = that.gather_stream_count(edge.source.data[":stats"], sani_stream, "600"); + text += stream + ": " + stream_transfered + ": " + (totaltrans > 0 ? Math.round((stream_transfered / totaltrans) * 100) : 0) + "%\n"; + + } + } + + texts[edge.source.name + edge.target.name] = text; + }); + + return texts; + }; + + this.calculate_weights = function(psys, totaltrans) { + var weights = {}; + + psys.eachEdge(function(edge, pt1, pt2) { + var trans = 0; + for (var i = 0; i < edge.target.data[":inputs"].length; i++) { + var stream = edge.target.data[":inputs"][i][":sani-stream"]; + if (edge.target.data[":inputs"][i][":component"] === edge.source.name) + trans += that.gather_stream_count(edge.source.data[":stats"], stream, "600"); + } + weights[edge.source.name + edge.target.name] = (totaltrans > 0 ? trans / totaltrans : 0); + }); + return weights; + }; + + this.calculate_total_transmitted = function(psys) { + var totaltrans = 0; + var countedmap = {} + psys.eachEdge(function(node, pt, pt2) { + if (!countedmap[node.source.name]) + countedmap[node.source.name] = {}; + + for (var i = 0; i < node.target.data[":inputs"].length; i++) { + var stream = node.target.data[":inputs"][i][":stream"]; + if (that.stream_checked(node.target.data[":inputs"][i][":sani-stream"])) { + if (!countedmap[node.source.name][stream]) { + if (node.source.data[":stats"]) { + var toadd = that.gather_stream_count(node.source.data[":stats"], node.target.data[":inputs"][i][":sani-stream"], "600"); + totaltrans += toadd; + } + countedmap[node.source.name][stream] = true; + } + } + } + + }); + + return totaltrans; + }; + + this.stream_checked = function(stream) { + // var checked = $("#" + stream).is(":checked"); + var checked = _.isEqual(stream.substr(0, 7), 'default'); + return checked; + }; + + this.gather_stream_count = function(stats, stream, time) { + var transferred = 0; + if (stats) + for (var i = 0; i < stats.length; i++) { + if (stats[i][":transferred"] != null) { + var stream_trans = stats[i][":transferred"][time][stream]; + if (stream_trans != null) + transferred += stream_trans; + } + } + return transferred; + }; + + return myRenderer; + }, + update_data: function(jdat, sys) { + _.each(jdat, function(k, v) { + if (sys.getNode(k)) + sys.getNode(k).data = v; + }); + }, + + has_checked_stream_input: function(inputs) { + for (var i = 0; i < inputs.length; i++) { + var x = this.stream_checked(inputs[i][":sani-stream"]); + if (x) + return true; + } + return false; + }, + + has_checked_stream_output: function(jdat, component) { + var that = this; + var ret = false; + $.each(jdat, function(k, v) { + for (var i = 0; i < v[":inputs"].length; i++) { + if (that.stream_checked(v[":inputs"][i][":sani-stream"]) && v[":inputs"][i][":component"] == component) + ret = true; + } + }); + return ret; + }, + + rechoose: function(jdat, sys, box) { + var that = this; + //Check each node in our json data to see if it has inputs from or outputs to selected streams. If it does, add a node for it. + $.each(jdat, function(k, v) { + if (that.has_checked_stream_input(v[":inputs"]) || that.has_checked_stream_output(jdat, k)) + sys.addNode(k, v); + }); + + //Check each node in our json data and add necessary edges based on selected components. + $.each(jdat, function(k, v) { + for (var i = 0; i < v[":inputs"].length; i++) + if (_.isEqual(v[":inputs"][i][":sani-stream"].substr(0, 7), 'default')) { + sys.addEdge(v[":inputs"][i][":component"], k, v); + } + }); + + //Tell the particle system's renderer that it needs to update its labels, colors, widths, etc. + sys.renderer.signal_update(); + sys.renderer.redraw(); + + } + + }); + + return topologyGraphView; +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js new file mode 100644 index 0000000..ba17fc5 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js @@ -0,0 +1,300 @@ +/** +* 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. +*/ + +define(['require', + 'modules/Vent', + 'models/VTopology', + 'collection/VTopologyList', + 'utils/TableLayout', + 'utils/LangSupport', + 'bootbox', + 'utils/Utils', + 'utils/Globals', + 'hbs!tmpl/topology/topologySummary', + 'bootstrap' +], function(require, vent, mTopology, cTopologyList, TableLayout, localization, bootbox, Utils, Globals, tmpl) { + 'use strict'; + + var TopologySummaryTableLayout = Marionette.LayoutView.extend({ + + template: tmpl, + + templateHelpers: function() {}, + + events: { + 'click [data-id="deployBtn"]': 'evDeployTopology' + }, + + ui: { + summaryDetails: '[data-id="summary"]' + }, + + regions: { + 'rTableList': '#summaryTable', + }, + + initialize: function() { + this.collection = new cTopologyList(); + vent.trigger('Breadcrumb:Hide'); + }, + + fetchSummary: function(flag) { + var that = this; + this.collection.fetch({ + success: function(collection, response, options) { + if (collection && collection.length) { + var arr = []; + _.each(collection.models[0].get('topologies'), function(object){ + arr.push(new mTopology(object)); + }); + that.countActive = 0; + that.collection.reset(arr); + that.showSummaryDetail(); + that.startPollingAction(); + } + }, + error: function(collection, response, options){ + that.startPollingAction(); + Utils.notifyError(response.statusText); + } + }) + }, + + onRender: function() { + this.showSummaryTable(this.collection); + $('.loading').hide(); + this.fetchSummary(); + this.showSummaryDetail(); + }, + + showSummaryDetail: function() { + var totalTopologies = 0, + activeTopologies = 0, + inactiveTopologies = 0; + if (this.collection && this.collection.length) { + totalTopologies = this.collection.length; + activeTopologies = this.countActive; + inactiveTopologies = this.collection.length - this.countActive; + } + var template = _.template('<label style="margin-right:10px">' + localization.tt('lbl.topologySummary') + ' </label>' + + '<span class="topology-summary-stats"><%- total%> ' + localization.tt('lbl.total') + '</span> | ' + + '<span class="topology-summary-stats"><%- active%> ' + localization.tt('lbl.active') + '</span> | ' + + '<span class="topology-summary-stats"><%- inactive%> ' + localization.tt('lbl.inactive') + '</span>'); + this.ui.summaryDetails.html(template({ + total: totalTopologies, + active: activeTopologies, + inactive: inactiveTopologies + })); + }, + + showSummaryTable: function(collection) { + this.rTableList.show(new TableLayout({ + columns: this.getColumns(), + collection: this.collection, + gridOpts: { + emptyText: localization.tt('msg.noTopologyFound') + } + })); + this.rTableList.$el.find('[data-id="r_tableList"]').attr("style","height:655px"); + }, + + getColumns: function() { + var that = this; + var cols = [{ + name: "name", + cell: "uri", + href: function(model) { + if(_.isEqual(model.get('status'),'ACTIVE')){ + that.countActive++; + } + return '#!/topology/' + model.get('id'); + }, + label: localization.tt("lbl.name"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryName") + }, { + name: "id", + cell: "string", + label: localization.tt("lbl.id"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryId") + }, { + name: "owner", + cell: "string", + label: localization.tt("lbl.owner"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryOwner") + }, { + name: "status", + cell: "string", + label: localization.tt("lbl.status"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryStatus") + }, { + name: "uptime", + cell: "string", + label: localization.tt("lbl.uptime"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryUptime") + }, { + name: "workersTotal", + cell: "string", + label: localization.tt("lbl.workers"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryWorkers") + }, { + name: "executorsTotal", + cell: "string", + label: localization.tt("lbl.executors"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryExecutors") + }, { + name: "tasksTotal", + cell: "string", + label: localization.tt("lbl.tasks"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryTasks") + }, { + name: "schedulerInfo", + cell: "string", + label: localization.tt("lbl.schedulerInfo"), + sortable: true, + editable: false, + hasTooltip: true, + tooltipText: localization.tt("msg.topologySummaryScheduler") + }]; + return cols; + }, + + evDeployTopology: function(e) { + var that = this; + + if (that.view) { + that.onDialogClosed(); + } + + require(['views/Topology/TopologyForm'], function(TopologyFormView) { + that.view = new TopologyFormView(); + that.view.render(); + + bootbox.dialog({ + message: that.view.el, + title: localization.tt('btn.deployNewTopology'), + className: "topology-modal", + buttons: { + cancel: { + label: localization.tt('btn.cancel'), + className: "btn-default", + callback: function() { + that.onDialogClosed(); + } + }, + success: { + label: localization.tt('btn.save'), + className: "btn-success", + callback: function() { + var errs = that.view.validate(); + if(_.isEmpty(errs)){ + that.submitTopology(); + } else return false; + } + } + } + }); + }); + }, + + submitTopology: function() { + Utils.notifyInfo(localization.tt("dialogMsg.topologyBeingDeployed")); + var attrs = this.view.getData(), + formData = new FormData(), + obj = {}, + url = Globals.baseURL + '/api/v1/uploadTopology', + that = this; + + if(!_.isEqual(attrs.jar.name.split('.').pop().toLowerCase(),'jar')){ + Utils.notifyError(localization.tt("dialogMsg.invalidFile")); + return false; + } + formData.append('topologyJar', attrs.jar); + obj.topologyMainClass = attrs.topologyClass; + obj.topologyMainClassArgs = []; + obj.topologyMainClassArgs.push(attrs.name); + + if(!_.isEmpty(attrs.arguments)){ + Array.prototype.push.apply(obj.topologyMainClassArgs,attrs.arguments.split(' ')); + } + + formData.append("topologyConfig", JSON.stringify(obj)); + + var successCallback = function(response){ + if(_.isString(response)){ + response = JSON.parse(response); + } + if(_.isEqual(response.status, 'failed')){ + Utils.notifyError(response.error); + } else { + Utils.notifySuccess(localization.tt("dialogMsg.topologyDeployedSuccessfully")); + that.fetchSummary(true); + } + }; + + var errorCallback = function(){ + Utils.notifyError(localization.tt("dialogMsg.topologyDeployFailed")); + }; + + Utils.uploadFile(url,formData,successCallback, errorCallback); + }, + + onDialogClosed: function() { + if (this.view) { + this.view.close(); + this.view.remove(); + this.view = null; + } + }, + + startPollingAction: function(){ + var that = this; + setTimeout(function() { + if(_.isEqual(typeof that.ui.summaryDetails, "object")){ + that.fetchSummary(); + } + }, Globals.settings.refreshInterval); + + } + + }); + return TopologySummaryTableLayout; +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/views/site/Header.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/site/Header.js b/contrib/views/storm/src/main/resources/scripts/views/site/Header.js new file mode 100644 index 0000000..966fe2f --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/site/Header.js @@ -0,0 +1,79 @@ +/** +* 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. +*/ + +define(['require', + 'modules/Vent', + 'utils/LangSupport', + 'hbs!tmpl/site/header'], function(require, vent, localization, headerTmpl){ + 'use strict'; + + var HeaderView = Marionette.LayoutView.extend({ + _viewNmae: 'Header', + + template: headerTmpl, + + templateHelpers: function() {}, + + regions: { + + }, + + ui: { + toplogyLink: '[data-id="topology"]', + clusterLink: '[data-id="cluster"]' + }, + + events: { + 'click [data-id="topology"]': 'showTopologySection', + 'click [data-id="cluster"]': 'showClusterSection' + }, + + initialize: function (options) { + this.clusterTabFlag = false; + this.bindEvent(); + }, + + bindEvent: function() { + var that = this; + vent.on('Breadcrumb:Show', function(name){ + that.$('.breadcrumb').removeClass('displayNone'); + that.$('#breadcrumbName').html(name); + }); + vent.on('Breadcrumb:Hide', function(){ + that.$('.breadcrumb').addClass('displayNone'); + }); + }, + + onRender: function () {}, + + showTopologySection: function () { + this.ui.clusterLink.parent().removeClass('active'); + this.ui.toplogyLink.parent().addClass('active'); + vent.trigger('Region:showTopologySection'); + }, + + showClusterSection: function () { + this.ui.toplogyLink.parent().removeClass('active'); + this.ui.clusterLink.parent().addClass('active'); + vent.trigger('Region:showClusterSection'); + } + + }); + + return HeaderView; +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/styles/default.css ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/styles/default.css b/contrib/views/storm/src/main/resources/styles/default.css new file mode 100644 index 0000000..9a08d82 --- /dev/null +++ b/contrib/views/storm/src/main/resources/styles/default.css @@ -0,0 +1,298 @@ +/** + * CSS Goes here + */ + +/* Generic */ +/*body { + color:#555; +}*/ +select { + padding: 3px 6px; + border: 2px #53c749 solid; + background-color: #fff; +} + +a:hover, a:focus { + text-decoration: none; +} + +[data-error]{ + color: red; +} + +.loading{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url('../images/loading.gif') no-repeat center center; + background-size: 4%; + background-color: rgba(255,255,255,0.7); + z-index: 99; +} + +/* Bootsrap Extended */ +.table-borderless > thead > tr > th, +.table-borderless > tbody > tr > th, +.table-borderless > tfoot > tr > th, +.table-borderless > thead > tr > td, +.table-borderless > tbody > tr > td, +.table-borderless > tfoot > tr > td { + border:none; +} + +.backgrid .ascending .sort-caret { + vertical-align: baseline; + border-top: 0; + border-right: 4px solid transparent; + border-bottom: 4px solid; + border-left: 4px solid transparent; +} + +.backgrid .descending .sort-caret { + vertical-align: super; + border-top: 4px solid; + border-right: 4px solid transparent; + border-bottom: 0; + border-left: 4px solid transparent; +} + +/*.tab-content>.tab-pane { + padding: 0 20px; +}*/ +.row-margin-bottom { + margin-bottom: 20px; +} +.sview-tabs .nav-tabs { + border-bottom: 2px #53c749 solid; + margin-bottom: 20px; +} +.sview-tabs .nav-tabs>li { + margin-bottom:0; + padding:10px 0; +} +.sview-tabs .nav-tabs>li>a { + color:#aaa; + font-size: 20px; + line-height:0.6; + border:none; + border-radius:0; + border-left:1px #BBB solid; +} +.sview-tabs .nav>li>a:hover { + background-color: transparent; + cursor: pointer; +} +.sview-tabs .nav-tabs>li:first-child>a { + border-left:none !important; +} +.sview-tabs .nav-tabs>li.active>a { + color:#333; + font-weight:bold; + border:none; + border-left:1px #BBB solid; +} +.topology-summary-stats { + color:#53c749; + margin-left: 5px; + margin-right: 5px; +} +.ui-widget-header { + border: 1px solid green; + background: green 50% 50% repeat-x; +} + +.topology-modal .modal-header { + color:#53c749; +} + +#topology .table-hover > thead > tr > th { + background-color: grey; +} + +#topology .table-hover > thead > tr > th > div > a{ + color: white; +} + +h3.topology-title { +color: #53c749; +margin-top: 0; +margin-bottom: 0; +} + +#topology .table-hover > tbody > tr:hover { + background-color: #C4ECC1; +} +.topology-tabs table tr.recent > td { + background-color: #3FC846; + color: #fff; + cursor: pointer; +} + +.topology-summary { + border: 2px #888 solid; + padding-left: 15px; + padding-left: 10px; +} +.topology-summary h4 { + color: #777; + font-weight: bold; + margin-bottom: 25px; +} +.topology-summary .table > tbody > tr > th, +.topology-summary .table > tbody > tr > td { + padding-top: 3px; + padding-bottom: 3px; +} +.topology-summary .table > tbody > tr > th { + font-weight: normal; + color: #999; + text-align: right; +} +.topology-summary .table > tbody > tr > td { + color:#53c749; +} + +.topology-graph { + border: 2px #53c749 solid; +} + +.statistics { + background-color: #F3F3F3; +} +.statistics h3 { + margin-top: 20px; + margin-bottom: 20px; +} +.topology-time-frame label { + font-weight: normal; +} + +.statistics-accordion .panel { + border-radius:0; + border: 2px #53c749 solid; +} +.statistics-accordion .panel-default > .panel-heading { + border-radius:0; + background:#fff; + color:#777; +} +.statistics-accordion .panel-heading + .panel-collapse > .panel-body { + border-top: 2px #53c749 solid; +} +.statistics-row { + border-bottom: 1px #53c749 solid; + margin-left: 20px; +} +.statistics-row:last-child { +border-bottom: 0; +} +.statistics-row.child { + padding-left: 30px; +} +.statistics-row h5 { + font-weight: bold; +} +.statistics .table > thead > tr > th, +.statistics .table > tbody > tr > td { + padding: 4px; +} +.statistics .table > thead > tr > th { + background-color: #f9f9f9; +} + +/* Clusters */ +.cluster-summary { + border: 2px #53c749 solid; + padding-left: 20px; + padding-right: 20px; +} +.cluster-summary h4 { + color: #777; + font-weight: bold; +} +.cluster-table > thead > tr > th, +.cluster-table > tbody > tr > td { + padding: 4px; +} +.cluster-table > thead > tr > th { + color: #000; +} +#topologyDetail .table > thead > tr > th > div > a { + color: black; + text-align: left; +} +.displayNone { + display: none; +} +[data-id="r_tableList"] > .table > thead > tr > th > div > a { + color: #000; +} + +/** + * Bootstrap Notification + */ +.notifications { + position: fixed; + z-index: 9999; +} + +/* Positioning */ +.notifications.top-right { + right: 10px; + top: 25px; +} + +.notifications.top-left { + left: 10px; + top: 25px; +} + +.notifications.bottom-left { + left: 10px; + bottom: 25px; +} + +.notifications.bottom-right { + right: 10px; + bottom: 25px; +} + +/* Notification Element */ +.notifications > div { + position: relative; + margin: 5px 0px; +} + +.error-notification { + position: absolute; + top: 0; + right: 5px; +} + +.breadcrumb { + line-height: 52px; + margin-left: 25px; + font-size: 12px; + color: #666; +} +.breadcrumb .seperator { + margin-left: 5px; + margin-right: 5px; +} +.statistics-container { + border: 1px solid #ddd; +} +.table-header { + border-left: 10px #53c749 solid; +} +th.sortable > div > a { + text-decoration: none; + white-space: nowrap; + cursor: pointer; +} +table tr.recent > td { + background-color: #3FC846; + color: #fff; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html b/contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html new file mode 100644 index 0000000..aa46a5a --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html @@ -0,0 +1,83 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<div class="row row-margin-bottom"> + <div class="col-md-6" data-id="clusterSummaryTable"></div> + <div class="col-md-12"> + <div class="cluster-summary"> + <h4>{{tt "h.clusterSummary"}}</h4> + <div class="row" id="clusterSummaryTable"></div> + </div> + </div> +</div> + +<div class="row row-margin-bottom"> + <div class="col-md-12" data-id="nbsSummary"> + <div class="panel-group statistics-accordion" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingOne"> + <h6 class="panel-title"> + <a data-toggle="collapse" href="#collapseNimbSum" aria-expanded="true" aria-controls="collapseNimbSum" class=""> + <i class="fa fa-caret-down"></i> {{tt "h.nimbusSummary"}}</a> + </h6> + </div> + <div id="collapseNimbSum" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true"> + <div class="panel-body"> + <div class="row" id="nbsSummaryTable"> </div> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="row row-margin-bottom"> + <div class="col-md-12" data-id="sprSummary"> + <div class="panel-group statistics-accordion" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingTwo"> + <h6 class="panel-title"> + <a data-toggle="collapse" href="#collapseSubSum" aria-expanded="true" aria-controls="collapseSubSum"> + <i class="fa fa-caret-down"></i> {{tt "h.supervisorSummary"}}</a> + </h6> + </div> + <div id="collapseSubSum" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> + <div class="panel-body"> + <div class="row" id="sprSummaryTable"> <div class="row"> </div> </div> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="row row-margin-bottom"> + <div class="col-md-12" data-id="nbsConfig"> + <div class="panel-group statistics-accordion" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingThree"> + <h6 class="panel-title"> + <a data-toggle="collapse" href="#collapseNbs" aria-expanded="true" aria-controls="collapseNbs"> + <i class="fa fa-caret-down"></i> {{tt "h.nimbusConfiguration"}}</a> + </h6> + </div> + <div id="collapseNbs" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> + <div class="panel-body"> <div class="row" id="nbsConfigTable"> </div> </div> + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/site/header.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/site/header.html b/contrib/views/storm/src/main/resources/templates/site/header.html new file mode 100644 index 0000000..ec6ad02 --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/site/header.html @@ -0,0 +1,23 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<div class="sview-tabs"> + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a role="tab" data-toggle="tab" data-id="topology">{{tt 'h.topologies'}}</a></li> + <li role="presentation"><a role="tab" data-toggle="tab" data-id="cluster">{{tt 'h.cluster'}}</a></li> + <span class="breadcrumb displayNone"><a href="#!/topology">{{tt 'h.topologies'}}</a> <i class="fa fa-angle-double-right seperator"></i><span id="breadcrumbName"></span></span> + </ul> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/spout/spoutItemView.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/spout/spoutItemView.html b/contrib/views/storm/src/main/resources/templates/spout/spoutItemView.html new file mode 100644 index 0000000..539fa18 --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/spout/spoutItemView.html @@ -0,0 +1,46 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<div> + <div class="row row-margin-bottom"> + <div class="col-md-12"> + <div class="statistics-container"> + <div data-id="SpoutsSummaryTable"></div> + + <div class="row statistics-row"> + <div class="col-md-12"> + <h5>{{tt 'lbl.outputStats'}}</h5> + <div data-id="OpstSummaryTable"></div> + </div> + </div> + + <div class="row statistics-row"> + <div class="col-md-12"> + <h5>{{tt 'lbl.executors'}}</h5> + <div data-id="ExtrSummaryTable"></div> + </div> + </div> + + <div class="row statistics-row"> + <div class="col-md-12"> + <h5>{{tt 'lbl.errors'}}</h5> + <div data-id="ErrorSummaryTable"></div> + </div> + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html b/contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html new file mode 100644 index 0000000..f75f1b5 --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html @@ -0,0 +1,108 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<div class="row row-margin-bottom"> + <div class="col-md-3"><h3 class="topology-title"></h3></div> + <div class="col-md-3 topology-time-frame"> + <label> {{tt 'lbl.selectTimeFrame'}} : </label> + <select id="tFrame"></select> + </div> + <div class="col-md-2"> + <form class="form-inline"> + <div class="checkbox"><label><input id="sysBolt" type="checkbox"> {{tt 'lbl.showSystemBolt'}} </label></div> + </form> + </div> + <div class="col-md-4"> + <div class="btn-group-sm pull-right"> + <button id="btnActivate" class="btn btn-success btn-sm">{{tt 'btn.activate'}} </button> + <button id="btnDeactivate" class="btn btn-success btn-sm">{{tt 'btn.deactivate'}} </button> + <button id="btnRebalance" class="btn btn-success btn-sm">{{tt 'btn.rebalance'}} </button> + <button id="btnKill" class="btn btn-success btn-sm">{{tt 'btn.kill'}} </button> + </div> + </div> +</div> + +<div class="row row-margin-bottom"> + <div id="topologyDetail" class="col-md-12"></div> +</div> + +<div class="row row-margin-bottom"> + <div class="col-md-9"> + <div id="graph" class="topology-graph"></div> + </div> + <div class="col-md-3"> + <div class="topology-summary"> + <h4 align="center">{{tt 'lbl.topologySummary'}} </h4> + <div id="topo-summary"></div> + </div> + </div> +</div> +<div class="row"> + <div class="col-md-12 statistics"> + <!--h3>Statistics <button class="pull-right btn btn-success btn-sm">Open All</button></h3--> + <h3>{{tt 'lbl.statistics'}}</h3> + <div class="panel-group statistics-accordion" role="tablist" aria-multiselectable="true"> + <!-- 1st Accordion Begin --> + <div class="panel panel-default"> + <div class="panel-heading" role="tab"> + <h6 class="panel-title"> + <a class="collapsed" data-toggle="collapse" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> + <i class="fa fa-caret-down"></i> {{tt 'lbl.spouts'}}</a> + </h6> + </div> + <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> + <div class="panel-body" id="SpoutsTable"></div> + </div> + </div> + <!-- 1st Accordion End --> + + <!-- 2nd Accordion Begin --> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingTwo"> + <h6 class="panel-title"> + <a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"><span class="fa fa-caret-down"></span> {{tt 'lbl.bolts'}}</a> + </h6> + </div> + <div id="collapseTwo" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingTwo"> + <div class="panel-body"> + <div class="row statistics-row"> + <div id="BoltsSummaryTable"></div> + </div> + </div> + </div> + </div> + <!-- 2nd Accordion End --> + + <!-- 3rd Accordion Begin --> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingThree"> + <h6 class="panel-title"> + <a class="collapsed" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree"><span class="fa fa-caret-down"></span> {{tt 'lbl.topologyConfig'}}</a> + </h6> + </div> + <div id="collapseThree" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingThree"> + <div class="panel-body"> + <div class="row statistics-row"> + <div id="TopologyConfigTable"></div> + </div> + </div> + </div> + </div> + <!-- 3rd Accordion End --> + + </div> + </div> +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/topology/topologyForm.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/topology/topologyForm.html b/contrib/views/storm/src/main/resources/templates/topology/topologyForm.html new file mode 100644 index 0000000..f78d08d --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/topology/topologyForm.html @@ -0,0 +1,8 @@ +<form class="form-horizontal"> + <fieldset> + <div class="" data-fields="name"></div> + <div class="" data-fields="jar"></div> + <div class="" data-fields="topologyClass"></div> + <div class="" data-fields="arguments"></div> + </fieldset> +</form> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/templates/topology/topologySummary.html ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/templates/topology/topologySummary.html b/contrib/views/storm/src/main/resources/templates/topology/topologySummary.html new file mode 100644 index 0000000..3626346 --- /dev/null +++ b/contrib/views/storm/src/main/resources/templates/topology/topologySummary.html @@ -0,0 +1,23 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<div class="row row-margin-bottom"> + <div class="col-md-6" data-id="summary"></div> + <div class="col-md-6"> + <button class="btn btn-success btn-sm pull-right" data-id="deployBtn"> {{tt 'btn.deployNewTopology'}} </button> + </div> +</div> +<div class="row" id="summaryTable"></div> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/view.xml ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/view.xml b/contrib/views/storm/src/main/resources/view.xml new file mode 100644 index 0000000..a047d25 --- /dev/null +++ b/contrib/views/storm/src/main/resources/view.xml @@ -0,0 +1,22 @@ +<!-- +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. Kerberos, LDAP, Custom. Binary/Htt +--> +<view> + <name>Storm_Monitoring</name> + <label>Storm Monitoring</label> + <version>0.1.0</version> + <description>Ambari view for Apache Storm</description> +</view> http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 108db64..62cf8eb 100644 --- a/pom.xml +++ b/pom.xml @@ -331,6 +331,9 @@ <exclude>contrib/views/slider/src/main/resources/ui/app/assets/javascripts/**</exclude> <exclude>contrib/views/slider/src/main/resources/ui/bower_components/**</exclude> <exclude>contrib/views/slider/src/main/resources/ui/runner.js</exclude> + <exclude>contrib/views/storm/src/main/resources/libs/**</exclude> + <exclude>contrib/views/storm/src/main/resources/styles/default.css</exclude> + <exclude>contrib/views/storm/src/main/resources/templates/**</exclude> <exclude>contrib/addons/package/deb/nagios_addon_deb_control</exclude> <exclude>contrib/addons/src/addOns/nagios/conf.d/hdp_mon_nagios_addons.conf</exclude> <exclude>contrib/views/*/.classpath</exclude>
