http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/utils/LangSupport.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/utils/LangSupport.js b/contrib/views/storm/src/main/resources/scripts/utils/LangSupport.js new file mode 100644 index 0000000..79822c7 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/utils/LangSupport.js @@ -0,0 +1,116 @@ +/** +* 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', 'globalize', 'gblMessages/message/en'], function(require, vent, Globalize) { + 'use strict'; + + var localization = {}; + + //This is just to suppress validation Engine Error when app starts + $.fn.validationEngine = function() {}; + + function setCulture(culture) { + if (typeof culture !== 'undefined') { + localization.culture = culture; + } else { + localization.culture = "en"; + } + Globalize.culture(localization.culture); + }; + + localization.setDefaultCulture = function() { + setCulture(); + }; + + localization.tt = function(label) { + var ret = label; + + var str = localization.localize(label, localization.culture); + if (typeof str !== 'undefined') { + return str; + } + + if (localization.culture !== 'en') { + if (typeof localization.culture !== 'undefined') + ret = (typeof localization.localize(label, "en") === 'undefined') ? label : localization.localize(label, "en"); + else { + ret = localization.localize(label, "en"); + } + } + return ret; + }; + + localization.localize = function(key, culture) { + return localization.byString(Globalize.findClosestCulture(culture).messages, key) || Globalize.cultures["default"].messages[key]; + }; + + localization.byString = function(o, s) { + s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties + s = s.replace(/^\./, ''); // strip a leading dot + var a = s.split('.'); + while (a.length) { + var n = a.shift(); + if (n in o) { + o = o[n]; + } else { + return; + } + } + return o; + }; + + localization.formatCurrency = function(label) { + var str = Globalize.format(parseFloat(label), 'c'); + if (typeof str !== 'undefined') { + return str; + } + }; + + localization.getMonthsAbbr = function() { + return Globalize.culture().calendars.standard.months.namesAbbr; + }; + + localization.getDaysOfWeek = function(label) { + return Globalize.culture().calendars.standard.days.namesAbbr; + }; + + localization.chooseCulture = function(culture) { + var dfd = $.Deferred(); + dfd.done(function(validationMessages) { + setCulture(culture); + vent.trigger('Layouts:rerender'); + }); + switch (culture) { + default: require(['gblMessages/message/en'], function() { + dfd.resolve(''); + console.log('Language Changed to en'); + }); + break; + } + }; + + localization.formatDate = function(val, format) { + if (!val) return ""; + require(['utils/Utils'], function(Utils) { + var valDate = Util.DBToDateObj(val); + return Globalize.format(valDate, format, localization.culture); + }); + }; + + return localization; +}); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js b/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js new file mode 100644 index 0000000..7b8a844 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js @@ -0,0 +1,218 @@ +/** +* 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', + 'utils/Utils', + 'backgrid', + 'bootstrap.filestyle', + 'backbone.forms'], function (require, Globals, Utils) { + 'use strict'; + + /********************************************************************** + * Backgrid related * + **********************************************************************/ + + /* + * HtmlCell renders any html code + * @class Backgrid.HtmlCell + * @extends Backgrid.Cell + */ + var HtmlCell = Backgrid.HtmlCell = Backgrid.Cell.extend({ + + /** @property */ + className: "html-cell", + + render: function () { + this.$el.empty(); + var rawValue = this.model.get(this.column.get("name")); + var formattedValue = this.formatter.fromRaw(rawValue, this.model); + this.$el.append(formattedValue); + this.delegateEvents(); + return this; + } + }); + + var UriCell = Backgrid.UriCell = Backgrid.Cell.extend({ + className: "uri-cell", + title: null, + target: "_blank", + + initialize: function (options) { + UriCell.__super__.initialize.apply(this, arguments); + this.title = options.title || this.title; + this.target = options.target || this.target; + }, + + render: function () { + this.$el.empty(); + var rawValue = this.model.get(this.column.get("name")); + var href = _.isFunction(this.column.get("href")) ? this.column.get('href')(this.model) : this.column.get('href'); + var klass = this.column.get("klass"); + var formattedValue = this.formatter.fromRaw(rawValue, this.model); + this.$el.append($("<a>", { + tabIndex: -1, + href: href, + title: this.title || formattedValue, + 'class' : klass + }).text(formattedValue)); + + if(this.column.has("iconKlass")){ + var iconKlass = this.column.get("iconKlass"); + var iconTitle = this.column.get("iconTitle"); + this.$el.find('a').append('<i class="'+iconKlass+'" title="'+iconTitle+'"></i>'); + } + this.delegateEvents(); + return this; + } + + }); + + + /** + Renders a checkbox for Provision Table Cell. + @class Backgrid.CheckboxCell + @extends Backgrid.Cell + */ + Backgrid.CheckboxCell = Backgrid.Cell.extend({ + + /** @property */ + className: "select-cell", + + /** @property */ + tagName: "td", + + /** @property */ + events: { + "change input[type=checkbox]": "onChange", + "click input[type=checkbox]": "enterEditMode" + }, + + /** + Initializer. If the underlying model triggers a `select` event, this cell + will change its checked value according to the event's `selected` value. + + @param {Object} options + @param {Backgrid.Column} options.column + @param {Backbone.Model} options.model + */ + initialize: function (options) { + + this.column = options.column; + if (!(this.column instanceof Backgrid.Column)) { + this.column = new Backgrid.Column(this.column); + } + + if(!this.column.has("checkedVal")){ + this.column.set("checkedVal", "true"); // it is not a boolean value for EPM + this.column.set("uncheckedVal", "false"); + } + + var column = this.column, model = this.model, $el = this.$el; + this.listenTo(column, "change:renderable", function (column, renderable) { + $el.toggleClass("renderable", renderable); + }); + + if (Backgrid.callByNeed(column.renderable(), column, model)){ + $el.addClass("renderable"); + } + + this.listenTo(model, "change:" + column.get("name"), function () { + if (!$el.hasClass("editor")){ + this.render(); + } + }); + + this.listenTo(model, "backgrid:select", function (model, selected) { + this.$el.find("input[type=checkbox]").prop("checked", selected).change(); + }); + + + }, + + /** + Focuses the checkbox. + */ + enterEditMode: function () { + this.$el.find("input[type=checkbox]").focus(); + }, + + /** + Unfocuses the checkbox. + */ + exitEditMode: function () { + this.$el.find("input[type=checkbox]").blur(); + }, + + /** + When the checkbox's value changes, this method will trigger a Backbone + `backgrid:selected` event with a reference of the model and the + checkbox's `checked` value. + */ + onChange: function () { + var checked = this.$el.find("input[type=checkbox]").prop("checked"); + this.model.set(this.column.get("name"), checked); + this.model.trigger("backgrid:selected", this.model, checked); + }, + + /** + Renders a checkbox in a table cell. + */ + render: function () { + var model = this.model, column = this.column; + var val = (model.get(column.get("name")) === column.get("checkedVal") || model.get(column.get("name")) === true) ? true : false; + var editable = Backgrid.callByNeed(column.editable(), column, model); + + this.$el.empty(); + + this.$el.append($("<input>", { + tabIndex: -1, + type: "checkbox", + checked: val, + disabled: !editable + })); + this.delegateEvents(); + return this; + } + + }); + + Backbone.Form.editors.Fileupload = Backbone.Form.editors.Base.extend({ + initialize: function(options){ + Backbone.Form.editors.Base.prototype.initialize.call(this, options); + this.template = _.template('<input type="file" name="fileInput" class="filestyle">'); + }, + render: function(){ + this.$el.html( this.template ); + this.$(":file").filestyle(); + return this; + }, + getValue: function(){ + return $('input[name="fileInput"]')[0].files[0]; + } + }); + + Backbone.ajax = function() { + var urlPart = arguments[0].url.split('url=')[0]; + var stormUrlPart = arguments[0].url.split('url=')[1]; + urlPart += 'url=' + encodeURIComponent(stormUrlPart); + arguments[0].url = urlPart; + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/utils/TableLayout.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/utils/TableLayout.js b/contrib/views/storm/src/main/resources/scripts/utils/TableLayout.js new file mode 100644 index 0000000..d827601 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/utils/TableLayout.js @@ -0,0 +1,106 @@ +/** +* 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. +*/ + +/************************************************************************** +-- Purpose: @file This is the common View file for displaying Table/Grid to be used overall in the application. +**************************************************************************/ + +define([ + 'require', + 'utils/LangSupport' +], function (require, Localize) { + 'use strict'; + + + var TablelayoutTmpl = '<div>'+ + '<div class="position-relative col-md-12">'+ + '<div data-id="r_tableList" class="table-responsive tableBorder"> </div>'+ + '<div data-id="r_tableSpinner"></div>'+ + '</div>'+ + '</div>'; + + var TableLayout = Marionette.LayoutView.extend( + /** @lends TableLayout */ + { + _viewName: 'TableLayout', + + template: TablelayoutTmpl, + + /** Layout sub regions */ + regions: { + 'rTableList': 'div[data-id="r_tableList"]', + 'rTableSpinner': 'div[data-id="r_tableSpinner"]' + }, + + /** ui selector cache */ + ui: {}, + + defaultGrid: { + className: 'table table-bordered table-hover table-condensed backgrid', + emptyText: 'No Records found!' + }, + + /** ui events hash */ + events: function () {}, + + /** + * intialize a new HDTableLayout Layout + * @constructs + */ + initialize: function (options) { + _.extend(this, _.pick(options, 'collection', 'columns')); + this.gridOpts = _.clone(this.defaultGrid,{}); + _.extend(this.gridOpts, options.gridOpts, { + collection: this.collection, + columns: this.columns + }); + + this.bindEvents(); + }, + + /** all events binding here */ + bindEvents: function () { + this.listenTo(this.collection, 'request', function () { + this.$('div[data-id="r_tableSpinner"]').addClass('loading'); + }, this); + this.listenTo(this.collection, 'sync', function () { + this.$('div[data-id="r_tableSpinner"]').removeClass('loading'); + }, this); + this.listenTo(this.collection, 'error', function () { + this.$('div[data-id="r_tableSpinner"]').removeClass('loading'); + }, this); + }, + + /** on render callback */ + onRender: function () { + this.renderTable(); + }, + + /** + * show table + */ + renderTable: function () { + this.rTableList.show(new Backgrid.Grid(this.gridOpts)); + }, + + /** on close */ + onClose: function () {}, + }); + + return TableLayout; +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/utils/Utils.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/utils/Utils.js b/contrib/views/storm/src/main/resources/scripts/utils/Utils.js new file mode 100644 index 0000000..72080d5 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/utils/Utils.js @@ -0,0 +1,133 @@ +/** +* 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/LangSupport', 'bootstrap.notify'], function(require, localization) { + 'use strict'; + + var Utils = {}; + + Utils.defaultErrorHandler = function(model, error) { + if (error.status == 401) { + console.log("ERROR 401 occured."); + } + }; + + Utils.uploadFile = function(restURL, data, successCallback, errorCallback){ + $.ajax({ + url: restURL, + data: data, + cache: false, + contentType: false, + processData: false, + type: 'POST', + success: successCallback, + error: errorCallback + }); + }; + + Utils.notifyError = function(message){ + $('.top-right').notify({ + message: { html: "<i class='fa fa-warning'></i> " + message}, + type: 'danger', + closable: true, + transition: 'fade', + fadeOut: { enabled: true, delay: 3000 } + }).show(); + }; + + Utils.notifySuccess = function(message){ + $('.top-right').notify({ + message: { html: "<i class='fa fa-check'></i> " + message}, + type: 'success', + closable: true, + transition: 'fade', + fadeOut: { enabled: true, delay: 3000 } + }).show(); + }; + + Utils.notifyInfo = function(message){ + $('.top-right').notify({ + message: { html: "<i class='fa fa-info'></i> " + message}, + type: 'warning', + closable: true, + transition: 'fade', + fadeOut: { enabled: true, delay: 3000 } + }).show(); + }; + + Utils.getStormHostDetails = function(){ + var url = location.pathname+'proxy?url='; + $.ajax({ + url: '/api/v1/clusters/', + cache: false, + type: 'GET', + async: false, + success: function(response){ + var result = JSON.parse(response); + if(_.isArray(result.items) && result.items.length){ + var flag = false; + _.each(result.items, function(object){ + if(!flag){ + $.ajax({ + url: object.href, + type: 'GET', + async: false, + success: function(res){ + var config = JSON.parse(res); + var hostname; + _.each(config.alerts, function(obj){ + if(obj.Alert.service_name === "STORM" && obj.Alert.definition_name === "storm_webui"){ + hostname = obj.Alert.host_name; + } + }); + if(_.isUndefined(hostname) || hostname == ""){ + Utils.notifyError(localization.tt('msg.stormNotRunning')); + } else { + var obj = _.findWhere(config.service_config_versions, {"service_name": "STORM"}); + if(!_.isUndefined(obj)){ + var stormConfig = _.findWhere(obj.configurations, {"type": "storm-site"}); + if(! _.isUndefined(stormConfig)){ + flag = true; + url += 'http://'+hostname+':'+stormConfig.properties['ui.port']; + } else { + Utils.notifyError(localization.tt('msg.stormNotRunning')); + } + } else { + Utils.notifyError(localization.tt('msg.stormNotRunning')); + } + } + }, + error: function(res){ + Utils.notifyError(localization.tt('msg.stormNotRunning')); + } + }); + } + }); + } else { + Utils.notifyError(localization.tt('msg.stormNotConfigured')); + } + }, + error: function(error){ + Utils.notifyError(localization.tt('msg.stormNotRunning')); + } + }); + return url; + }; + + return Utils; +}); \ 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/Cluster/ClusterSummary.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js b/contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js new file mode 100644 index 0000000..03369ac --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js @@ -0,0 +1,381 @@ +/** +* 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/Cluster', + 'models/VNimbus', + 'models/VSupervisor', + 'models/VNimbusConfig', + 'utils/TableLayout', + 'utils/LangSupport', + 'utils/Globals', + 'utils/Utils', + 'hbs!tmpl/cluster/clusterSummary', + 'backgrid' +], function(require, vent, vCluster, vNimbus, vSupervisor, vNimbusConfig, TableLayout, localization, Globals, Utils, tmpl) { + 'use strict'; + + var ClusterSummaryTableLayout = Marionette.LayoutView.extend({ + + template: tmpl, + + templateHelpers: function() {}, + + ui: { + + clusterSummaryDetails: '[data-id="clusterSummary"]', + nbsSummaryDetails: '[data-id="nbsSummary"]', + sprsSummaryDetails: '[data-id="sprSummary"]', + nbsConfigDetails: '[data-id="nbsConfig"]' + }, + + regions: { + 'rCluster': '#clusterSummaryTable', + 'rNbsList': '#nbsSummaryTable', + 'rSprList': '#sprSummaryTable', + 'rnbsConfigList': '#nbsConfigTable' + }, + + initialize: function() { + this.clusterModel = new vCluster(); + this.supervisorModel = new vSupervisor(); + this.nimbusSummaryModel = new vNimbus(); + this.nimbusConfigModel = new vNimbusConfig(); + + this.clusterCollection = new Backbone.Collection(); + this.sprCollection = new Backbone.Collection(); + this.nimbusConfigCollection = new Backbone.Collection(); + this.nbsCollection = new Backbone.Collection(); + + }, + + onRender: function() { + this.showCtrSummary(this.clusterCollection); + this.showNbsSummary(this.nbsCollection); + this.showSprSummary(this.sprCollection); + this.showNbsConSummary(this.nimbusConfigCollection); + this.fetchData(); + + this.$('.collapse').on('shown.bs.collapse', function() { + $(this).parent().find(".fa-caret-right").removeClass("fa-caret-right").addClass("fa-caret-down"); + }).on('hidden.bs.collapse', function() { + $(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-right"); + }); + + }, + fetchData: function() { + this.getClusterSummary(this.clusterModel); + this.getSupervisorSummary(this.supervisorModel); + this.getNimbusConfig(this.nimbusConfigModel); + this.getNimbusSummary(this.nimbusSummaryModel); + }, + + getClusterSummary: function(model) { + var that = this; + this.clusterCollection.trigger('request', this.clusterCollection); + model.fetch({ + success: function(model, response, options) { + that.clusterCollection.trigger('sync', that.clusterCollection); + if (model) { + that.clusterCollection.reset(model); + } + that.startClusterSumPolling(); + }, + error: function(model, response, options) { + that.clusterCollection.trigger('error', that.clusterCollection); + that.startClusterSumPolling(); + Utils.notifyError(response.statusText); + return null; + } + }); + }, + + getSupervisorSummary: function(model) { + var that = this; + this.sprCollection.trigger('request', this.sprCollection); + model.fetch({ + success: function(model, response, options) { + that.sprCollection.trigger('sync', that.sprCollection); + if (model.has('supervisors') && model.get('supervisors').length) { + var arr = []; + _.each(model.get('supervisors'), function(object) { + arr.push(new vSupervisor(object)) + }); + that.sprCollection.reset(arr); + } + that.startSupervisorSumPolling(); + }, + error: function(model, response, options) { + that.sprCollection.trigger('error', that.sprCollection); + that.startSupervisorSumPolling(); + Utils.notifyError(response.statusText); + } + }); + }, + + getNimbusConfig: function(model) { + var that = this; + this.nimbusConfigCollection.trigger('request', this.nimbusConfigCollection); + model.fetch({ + success: function(model, response, options) { + that.nimbusConfigCollection.trigger('sync', that.nimbusConfigCollection); + if (model) { + var arr = []; + for(var key in model.attributes){ + var obj = {}; + obj.key = key; + obj.value = model.get(key); + arr.push(new vNimbusConfig(obj)); + } + that.nimbusConfigCollection.reset(arr); + } + that.startNimbusConfigPolling(); + }, + error: function(model, response, options) { + that.nimbusConfigCollection.trigger('error', that.nimbusConfigCollection); + that.startNimbusConfigPolling(); + Utils.notifyError(response.statusText); + } + }); + }, + + getNimbusSummary: function(model){ + var that = this; + this.nbsCollection.trigger('request', this.nbsCollection); + model.fetch({ + success: function(model, response, options) { + that.nbsCollection.trigger('sync', that.nbsCollection); + if (model.has('nimbuses') && model.get('nimbuses').length) { + var arr = []; + _.each(model.get('nimbuses'), function(object) { + arr.push(new vNimbus(object)) + }); + that.nbsCollection.reset(arr); + } + that.startNimbusSummaryPolling(); + }, + error: function(model, response, options) { + that.nbsCollection.trigger('error', that.nbsCollection); + that.startNimbusSummaryPolling(); + Utils.notifyError(response.statusText); + } + }); + }, + + showCtrSummary: function(collection) { + this.rCluster.show(new TableLayout({ + columns: this.getCtrColumns(), + collection: collection, + gridOpts: { + emptyText: localization.tt('msg.noClusterFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + showNbsSummary: function(collection) { + this.rNbsList.show(new TableLayout({ + columns: this.getNbsColumns(), + collection: this.nbsCollection, + gridOpts: { + emptyText: localization.tt('msg.noNimbusFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + showSprSummary: function(collection) { + this.rSprList.show(new TableLayout({ + columns: this.getSprColumns(), + collection: collection, + gridOpts: { + emptyText: localization.tt('msg.noSupervisorFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + showNbsConSummary: function(collection) { + this.rnbsConfigList.show(new TableLayout({ + columns: this.getNbsConColumns(), + collection: collection, + gridOpts: { + emptyText: localization.tt('msg.noNimbusConfigFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + getCtrColumns: function() { + return [{ + name: "supervisors", + cell: "string", + label: localization.tt("lbl.supervisors"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySupervisors') + + }, { + name: "slotsUsed", + cell: "string", + label: localization.tt("lbl.usedSlots"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySlots') + }, { + name: "slotsFree", + cell: "string", + label: localization.tt("lbl.freeSlots"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySlots') + + }, { + name: "slotsTotal", + cell: "string", + label: localization.tt("lbl.totalSlots"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySlots') + }, { + name: "executorsTotal", + cell: "string", + label: localization.tt("lbl.executors"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummaryExecutors') + }, { + name: "tasksTotal", + cell: "string", + label: localization.tt("lbl.tasks"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummaryTasks') + }]; + }, + + getNbsColumns: function() { + return [{ + name: "host", + cell: "string", + label: localization.tt("lbl.host") + }, { + name: "port", + cell: "string", + label: localization.tt("lbl.port") + }, { + name: "status", + cell: "string", + label: localization.tt("lbl.status") + }, { + name: "version", + cell: "string", + label: localization.tt("lbl.version") + }, { + name: "nimbusUpTime", + cell: "string", + label: localization.tt("lbl.uptimeSeconds") + }, { + name: "logs", + cell: "Html", + label: '', + formatter: _.extend({}, Backgrid.CellFormatter.prototype, { + fromRaw: function(rawValue, model) { + if (model) { + return "<a href="+model.get('nimbusLogLink')+" target='_blank' class='btn btn-success btn-xs center-block'>"+localization.tt('lbl.viewLogs')+"</a>"; + } + } + }) + } + ]; + }, + + getSprColumns: function() { + return [{ + name: "id", + cell: "string", + label: localization.tt("lbl.id"), + hasTooltip: true, + tooltipText: localization.tt('msg.supervisorId') + }, { + name: "host", + cell: "string", + label: localization.tt("lbl.host"), + hasTooltip: true, + tooltipText: localization.tt('msg.supervisorHost') + }, { + name: "uptime", + cell: "string", + label: localization.tt("lbl.uptime"), + hasTooltip: true, + tooltipText: localization.tt('msg.supervisorUptime') + }, { + name: "slotsTotal", + cell: "string", + label: localization.tt("lbl.slots"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySlots') + }, { + name: "slotsUsed", + cell: "string", + label: localization.tt("lbl.usedSlots"), + hasTooltip: true, + tooltipText: localization.tt('msg.clusterSummarySlots') + } + ]; + }, + + getNbsConColumns: function() { + var cols = [{ + name: "key", + cell: "string", + label: localization.tt("lbl.key"), + }, { + name: "value", + cell: "string", + label: localization.tt("lbl.value") + }]; + return cols; + }, + + startClusterSumPolling: function(){ + var that = this; + setTimeout(function(){ + that.getClusterSummary(that.clusterModel); + }, Globals.settings.refreshInterval); + }, + + startSupervisorSumPolling: function(){ + var that = this; + setTimeout(function(){ + that.getSupervisorSummary(that.supervisorModel); + }, Globals.settings.refreshInterval); + }, + + startNimbusConfigPolling: function(){ + var that = this; + setTimeout(function(){ + that.getNimbusConfig(that.nimbusConfigModel); + }, Globals.settings.refreshInterval); + }, + + startNimbusSummaryPolling: function(){ + var that = this; + setTimeout(function(){ + that.getNimbusSummary(that.nimbusSummaryModel); + }, Globals.settings.refreshInterval); + } + + }); + return ClusterSummaryTableLayout; +}); \ 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/Spout/SpoutCollectionView.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutCollectionView.js b/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutCollectionView.js new file mode 100644 index 0000000..eadab4d --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutCollectionView.js @@ -0,0 +1,53 @@ +/** +* 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', + 'views/Spout/SpoutItemView' + ], function(require, vSpoutItemView) { + 'use strict'; + + var spoutCollectionView = Marionette.CollectionView.extend({ + childView: vSpoutItemView, + + childViewOptions: function() { + return { + collection: this.collection, + topologyId: this.topologyId, + systemBoltFlag: this.systemBoltFlag, + windowTimeFrame: this.windowTimeFrame, + emptyMsg: "No spouts" + }; + }, + + initialize: function(options) { + this.collection = options.collection; + if(options.collection.length == 0){ + this.collection.add(new Backbone.Model()); + } + this.topologyId = options.topologyId; + this.systemBoltFlag = options.systemBoltFlag; + this.windowTimeFrame = options.windowTimeFrame; + }, + + onRender: function(){} + + }); + + return spoutCollectionView; +}); \ 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/Spout/SpoutItemView.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutItemView.js b/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutItemView.js new file mode 100644 index 0000000..f41e8d1 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Spout/SpoutItemView.js @@ -0,0 +1,355 @@ +/** +* 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/LangSupport', + 'models/VOutputStat', + 'models/VExecutor', + 'models/VError', + 'utils/TableLayout', + 'hbs!tmpl/spout/spoutItemView' +], function(require, localization, vOutputStat, vExecutors, vError, TableLayout, tmpl) { + 'use strict'; + + var spoutItemView = Marionette.ItemView.extend({ + template: tmpl, + tagName: 'div', + templateHelpers: function() { + return { + id: this.model.id, + name: this.model.get('name') + }; + }, + initialize: function(options) { + this.spoutsCollection = new Backbone.Collection(); + options.model.opstCollection = new Backbone.Collection(); + options.model.extrCollection = new Backbone.Collection(); + options.model.errorCollection = new Backbone.Collection(); + if(!_.isUndefined(options.topologyId) && options.model.has('errorWorkerLogLink')){ + this.getDetails(options.model, options.topologyId, options.systemBoltFlag, options.windowTimeFrame); + } + }, + + events: {}, + + onRender: function() { + this.showSpoutsSummaryTable(); + this.showOpstSummaryTable(); + }, + + getDetails: function(model, topologyId, systemBoltFlag, windowTimeFrame) { + var that = this; + this.spoutsCollection.trigger('request', this.spoutsCollection); + model.getDetails({ + topologyId: topologyId, + spoutId: model.get('spoutId'), + systemBoltFlag: systemBoltFlag, + windowTimeFrame: windowTimeFrame, + success: function(spoutsModel, response, options) { + that.spoutsCollection.trigger('sync', that.spoutsCollection); + if (spoutsModel) { + spoutsModel = new Backbone.Model(spoutsModel); + if (spoutsModel.has('outputStats') && spoutsModel.get('outputStats').length) { + + var arr = []; + _.each(spoutsModel.get('outputStats'), function(object) { + arr.push(new vOutputStat(object)) + }); + model.opstCollection.reset(arr); + } + + if (spoutsModel.has('executorStats') && spoutsModel.get('executorStats').length) { + var arr = []; + _.each(spoutsModel.get('executorStats'), function(object) { + arr.push(new vExecutors(object)) + }); + model.extrCollection.reset(arr); + } + + if (spoutsModel.has('componentErrors') && spoutsModel.get('componentErrors').length) { + + var arr = []; + _.each(spoutsModel.get('componentErrors'), function(object) { + arr.push(new vError(object)) + }); + model.errorCollection.reset(arr); + } + + that.spoutsCollection.reset(model); + } + }, + error: function() { + that.spoutsCollection.trigger('error', that.spoutsCollection); + return null; + } + }); + }, + + showSpoutsSummaryTable: function() { + + this.$('[data-id="SpoutsSummaryTable"]').html(new TableLayout({ + columns: this.getSpoutColumns(), + collection: this.spoutsCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noSpoutFound'), + className: 'table table-borderless table-striped table-header' + } + }).render().$el); + }, + + showOpstSummaryTable: function() { + var that = this; + + that.$('[data-id="OpstSummaryTable"]').html(new TableLayout({ + columns: that.getOpstColumns(), + collection: that.model.opstCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noOutputStatsFound'), + className: 'table table-borderless table-striped' + } + }).render().$el); + + that.$('[data-id="ExtrSummaryTable"]').html(new TableLayout({ + columns: that.getExtrColumns(), + collection: that.model.extrCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noExecutorsFound'), + className: 'table table-borderless table-striped' + } + }).render().$el); + + that.$('[data-id="ErrorSummaryTable"]').html(new TableLayout({ + columns: that.getErrorColumns(), + collection: that.model.errorCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noErrorFound'), + className: 'table table-borderless table-striped' + } + }).render().$el); + }, + + + getSpoutColumns: function() { + var cols = [{ + name: "spoutId", + cell: "string", + label: localization.tt('lbl.id'), + sortable: true, + hasTooltip: true, + tooltipText: localization.tt('msg.spoutId') + }, { + name: "executors", + cell: "string", + label: localization.tt('lbl.executors'), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutExecutors') + }, { + name: "tasks", + cell: "string", + label: localization.tt('lbl.tasks'), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutTasks') + }, { + name: "emitted", + cell: "string", + label: localization.tt('lbl.emitted'), + hasTooltip: true, + tooltipText: localization.tt('msg.emitted') + }, { + name: "transferred", + cell: "string", + label: localization.tt('lbl.transferred'), + hasTooltip: true, + tooltipText: localization.tt('msg.transferred') + }, { + name: "completeLatency", + cell: "string", + label: localization.tt('lbl.completeLatency'), + hasTooltip: true, + tooltipText: localization.tt('msg.completeLatency') + }, { + name: "acked", + cell: "string", + label: localization.tt('lbl.acked'), + hasTooltip: true, + tooltipText: localization.tt('msg.acked') + }, { + name: "failed", + cell: "string", + label: localization.tt('lbl.failed'), + hasTooltip: true, + tooltipText: localization.tt('msg.failed') + }]; + return cols; + }, + + getOpstColumns: function() { + var cols = [{ + name: "stream", + cell: "string", + label: localization.tt('lbl.stream'), + hasTooltip: true, + tooltipText: localization.tt('msg.stream'), + sortable: true + }, { + name: "emitted", + cell: "string", + label: localization.tt('lbl.emitted'), + hasTooltip: true, + tooltipText: localization.tt('msg.emitted') + }, { + name: "transferred", + cell: "string", + label: localization.tt('lbl.transferred'), + hasTooltip: true, + tooltipText: localization.tt('msg.transferred') + }, { + name: "completeLatency", + cell: "string", + label: localization.tt('lbl.completeLatencyMS'), + hasTooltip: true, + tooltipText: localization.tt('msg.completeLatency') + }, { + name: "acked", + cell: "string", + label: localization.tt('lbl.acked'), + hasTooltip: true, + tooltipText: localization.tt('msg.acked') + }, { + name: "failed", + cell: "string", + label: localization.tt('lbl.failed'), + hasTooltip: true, + tooltipText: localization.tt('msg.failed') + }]; + return cols; + }, + + getExtrColumns: function() { + var cols = [{ + name: "id", + cell: "string", + label: localization.tt('lbl.id'), + hasTooltip: true, + tooltipText: localization.tt('msg.uniqueExecutorId'), + sortable: true + }, { + name: "uptime", + cell: "string", + label: localization.tt('lbl.uptime'), + hasTooltip: true, + tooltipText: localization.tt('msg.extensionUptime') + }, { + name: "host", + cell: "string", + label: localization.tt('lbl.host'), + hasTooltip: true, + tooltipText: localization.tt('msg.extensionHost') + }, { + name: "port", + cell: "string", + label: localization.tt('lbl.port'), + hasTooltip: true, + tooltipText: localization.tt('msg.extensionPort') + }, { + name: "emitted", + cell: "string", + label: localization.tt('lbl.emitted'), + hasTooltip: true, + tooltipText: localization.tt('msg.emitted') + }, { + name: "transferred", + cell: "string", + label: localization.tt('lbl.transferred'), + hasTooltip: true, + tooltipText: localization.tt('msg.transferred') + }, { + name: "completeLatency", + cell: "string", + label: localization.tt('lbl.completeLatencyMS'), + hasTooltip: true, + tooltipText: localization.tt('msg.completeLatency') + }, { + name: "acked", + cell: "string", + label: localization.tt('lbl.acked'), + hasTooltip: true, + tooltipText: localization.tt('msg.acked') + }, { + name: "failed", + cell: "string", + label: localization.tt('lbl.failed'), + hasTooltip: true, + tooltipText: localization.tt('msg.failed') + }, { + name: "logs", + cell: "Html", + label: '', + sortable: false, + formatter: _.extend({}, Backgrid.CellFormatter.prototype, { + fromRaw: function(rawValue, model) { + if (model) { + return "<a href="+model.get('workerLogLink')+" target='_blank' class='btn btn-success btn-xs center-block'>"+localization.tt('lbl.viewLogs')+"</a>"; + } + } + }) + }]; + return cols; + }, + + getErrorColumns: function() { + var cols = [ + { + name: "time", + cell: "string", + label: localization.tt('lbl.time'), + sortable: true + }, { + name: "errorHost", + cell: "string", + label: localization.tt('lbl.errorHost'), + }, { + name: "errorPort", + cell: "string", + label: localization.tt('lbl.errorPort'), + }, { + name: "error", + cell: "string", + label: localization.tt('lbl.error'), + } + ]; + return cols; + }, + + onClose: function() {} + }); + return spoutItemView; +}); \ 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/RebalanceForm.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Topology/RebalanceForm.js b/contrib/views/storm/src/main/resources/scripts/views/Topology/RebalanceForm.js new file mode 100644 index 0000000..3b35c71 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Topology/RebalanceForm.js @@ -0,0 +1,84 @@ +/** +* 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(['utils/LangSupport', + 'utils/Globals', + 'backbone.forms' + ], function (localization, Globals) { + 'use strict'; + + var RebalanceForm = Backbone.Form.extend({ + + initialize: function (options) { + this.spoutCollection = options.spoutCollection; + this.boltCollection = options.boltCollection; + Backbone.Form.prototype.initialize.call(this, options); + }, + + schema: function () { + var that = this; + var obj = { + workers: { + type: 'Number', + title: localization.tt('lbl.workers') + } + }; + + if(that.spoutCollection.length){ + _.each(that.spoutCollection.models, function(model){ + if(model.has('spoutId')) { + obj[model.get('spoutId')] = { + type: 'Number', + title: model.get('spoutId') + }; + } + }); + } + if(that.boltCollection.length){ + _.each(that.boltCollection.models, function(model){ + if(model.has('boltId')) { + obj[model.get('boltId')] = { + type: 'Number', + title: model.get('boltId') + }; + } + }); + } + obj.waitTime = { + type: 'Number', + title: localization.tt('lbl.waitTime')+'*', + validators: ['required'] + } + return obj + }, + + render: function(options){ + Backbone.Form.prototype.render.call(this,options); + }, + + getData: function () { + return this.getValue(); + }, + + close: function () { + console.log('Closing form view'); + } + }); + + return RebalanceForm; +}); \ 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/TopologyDetail.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyDetail.js b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyDetail.js new file mode 100644 index 0000000..ec9c4fc --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyDetail.js @@ -0,0 +1,734 @@ +/** +* 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', + 'modules/Vent', + 'utils/LangSupport', + 'models/VTopology', + 'models/VSpout', + 'models/VBolt', + 'models/VTopologyConfig', + 'views/Spout/SpoutCollectionView', + 'views/Topology/TopologyGraphView', + 'utils/TableLayout', + 'utils/Utils', + 'bootbox', + 'hbs!tmpl/topology/topologyDetail' +], function(require, Globals, vent, localization, vTopology, vSpout, vBolt, vTopologyConfig, vSpoutCollectionView, vTopologyGraphView, TableLayout, Utils, bootbox, tmpl) { + + 'use strict'; + + var masterView = Marionette.LayoutView.extend({ + + template: tmpl, + + regions: { + 'rTopologyDetailsTbl': '#topologyDetail', + 'rTopologyGraph': '#graph', + 'rTopologySummary': '#topo-summary', + 'rSpoutsTable': '#SpoutsTable', + 'rBoltsSummaryTable': '#BoltsSummaryTable', + 'rTopologyConfigTable': '#TopologyConfigTable' + }, + + ui: { + topologySummary: '#topo-summary', + summaryLoader: '#summaryLoader', + BoltsSummaryDetails: '[data-id="BoltsSummary"]' + }, + + events: { + 'change #tFrame': 'evChangeTimeFrame', + 'click #btnActivate': 'evActivateTopology', + 'click #btnDeactivate': 'evDeactivateTopology', + 'click #btnRebalance': 'evRebalanceTopology', + 'click #btnKill': 'evKillTopology', + 'click #openAll': 'openAllTables', + 'change #sysBolt': 'evSysBoltToggle' + }, + + initialize: function(options) { + this.model = new vTopology(); + this.systemBoltFlag = false; + this.topologyDetailsColl = new Backbone.Collection(); + this.summaryArr = []; + this.windowTimeFrame = ":all-time"; + this.fetchData(options.id, this.systemBoltFlag, this.windowTimeFrame); + this.generateTemplate(); + + this.spoutsCollection = new Backbone.Collection(); + this.boltsCollection = new Backbone.Collection(); + this.topoConfigCollection = new Backbone.Collection(); + }, + + fetchData: function(id, flag, timeFrame){ + var that = this; + $('.loading').show(); + this.model.getDetails({ + id: id, + sysBoltFlag: flag, + windowTimeFrame: timeFrame, + success: function(model, response, options) { + that.model = new vTopology(model); + that.getDetails(that.model); + that.render(); + that.disableBtnAction(model.status); + that.$('#sysBolt').prop("checked",that.systemBoltFlag) + that.startPollingAction(that.model.get('id'), that.model.get('window')); + $('.loading').hide(); + }, + error: function(model, response, options) { + that.startPollingAction(that.model.get('id'), that.model.get('window')); + $('.loading').hide(); + Utils.notifyError(model.statusText); + } + }); + }, + + generateTemplate: function() { + this.summaryTemplate = _.template('<table class="table table-borderless"><tbody>' + + '<tr>' + + '<th>'+localization.tt('lbl.emitted')+'</th>' + + '<td><%if (emitted) { %> <%=emitted%> <%} else { %> 0 <% } %></td>' + + '</tr>' + + '<tr>' + + '<th>'+localization.tt('lbl.transferred')+'</th>' + + '<td><%if (transferred) { %> <%=transferred%> <%} else { %> 0 <% } %></td>' + + '</tr>' + + '<tr>' + + '<th>'+localization.tt('lbl.completeLatency')+'</th>' + + '<td><%if (completeLatency) { %> <%=completeLatency%> <%} else { %> 0 <% } %></td>' + + '</tr>' + + '<tr>' + + '<th>'+localization.tt('lbl.acked')+'</th>' + + '<td><%if (acked) { %> <%=acked%> <%} else { %> 0 <% } %></td>' + + '</tr>' + + '<tr>' + + '<th>'+localization.tt('lbl.failed')+'</th>' + + '<td><%if (failed) { %> <%=failed%> <%} else { %> 0 <% } %></td>' + + '</tr>' + + '</tbody></table>'); + + }, + + onRender: function() { + if(! this.$el.hasClass('topologyDetailView')){ + this.$el.addClass('topologyDetailView'); + } + this.$('.topology-title').html(this.model.has('name') ? this.model.get('name') : ''); + this.showDetailsTable(this.topologyDetailsColl); + if(this.summaryArr.length){ + this.setTimeFrameOptions(); + } + this.windowTimeFrame = this.model.get('window'); + this.$('#tFrame').val(this.windowTimeFrame); + this.showSummaryTable(this.windowTimeFrame); + + this.showBoltsSummaryTable(); + this.showTopologyConfigTable(); + + this.showSpoutsSummaryTable(); + + if(this.model.has('id')){ + this.rTopologyGraph.show(new vTopologyGraphView({ + id: this.model.get('id') + })); + } + + this.$('.collapse').on('shown.bs.collapse', function() { + $(this).parent().find(".fa-caret-right").removeClass("fa-caret-right").addClass("fa-caret-down"); + }).on('hidden.bs.collapse', function() { + $(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-right"); + }); + + this.$('[data-id="r_tableList"]').parent().removeClass('col-md-12'); + if(this.$el.parent().hasClass('active')){ + this.showBreadCrumbs(); + } + }, + + disableBtnAction: function(status){ + _.each(this.$el.find('.btn.btn-success.btn-sm'),function(elem){ + $(elem).removeAttr('disabled') + }); + switch(status){ + case "ACTIVE": + this.$el.find('#btnActivate').attr('disabled','disabled'); + break; + case "INACTIVE": + this.$el.find('#btnDeactivate').attr('disabled','disabled'); + break; + case "REBALANCING": + this.$el.find('#btnRebalance').attr('disabled','disabled'); + break; + case "KILLED": + this.$el.find('#btnKill').attr('disabled','disabled'); + break; + } + }, + + setTimeFrameOptions: function() { + var html = ''; + _.each(this.summaryArr, function(obj){ + switch(obj.window){ + case "600": + obj.windowPretty = localization.tt('lbl.last10Min'); + break; + case "10800": + obj.windowPretty = localization.tt('lbl.last3Hr'); + break; + case "86400": + obj.windowPretty = localization.tt('lbl.last1Day'); + break; + } + html += "<option value="+obj.window+">"+obj.windowPretty+"</option>"; + }); + this.$('#tFrame').append(html); + }, + + evChangeTimeFrame: function(e) { + this.windowTimeFrame = $(e.currentTarget).val(); + this.fetchData(this.model.get('id'), this.systemBoltFlag, this.windowTimeFrame); + }, + + getDetails: function(model) { + var detModel = new Backbone.Model(_.pick(model.attributes, 'name', 'id', 'owner', 'status', 'uptime', 'workersTotal', 'executorsTotal', 'tasksTotal', 'schedulerInfo')); + + this.topologyDetailsColl.reset(detModel); + + this.summaryArr = model.get('topologyStats'); + + var that = this; + + var spoutsModel = new vSpout(); + + var s_arr = []; + _.each(model.get('spouts'), function(spout){ + var spoutsModel = new vSpout(spout); + s_arr.push(spoutsModel) + }); + that.spoutsCollection.reset(s_arr); + + var b_arr =[]; + _.each(this.model.get("bolts"), function(object){ + b_arr.push(new vBolt(object)); + }); + that.boltsCollection.reset(b_arr); + + var topoConfigModel = this.model.get("configuration"); + if (model) { + var arr = []; + for(var key in topoConfigModel){ + var obj = {}; + obj.key = key; + obj.value = topoConfigModel[key]; + arr.push(new vTopologyConfig(obj)); + } + that.topoConfigCollection.reset(arr); + } + }, + + showSpoutsSummaryTable: function() { + this.rSpoutsTable.show(new vSpoutCollectionView({ + collection: this.spoutsCollection, + systemBoltFlag: this.systemBoltFlag, + topologyId: this.model.get('id'), + windowTimeFrame: this.windowTimeFrame + })); + }, + + showBoltsSummaryTable: function() { + + this.rBoltsSummaryTable.show(new TableLayout({ + columns: this.getBoltColumns(), + collection: this.boltsCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noBoltFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + showTopologyConfigTable: function() { + this.rTopologyConfigTable.show(new TableLayout({ + columns: this.getTopoConfigColumns(), + collection: this.topoConfigCollection, + includeFilter: false, + includePagination: false, + includeFooterRecords: false, + gridOpts: { + emptyText: localization.tt('msg.noTopologyConfigFound'), + className: 'table table-borderless table-striped cluster-table' + } + })); + }, + + + showDetailsTable: function(collection) { + this.rTopologyDetailsTbl.show(new TableLayout({ + columns: this.getColumns(), + collection: collection, + gridOpts: { + className: 'table table-bordered table-striped backgrid' + } + })); + }, + + getColumns: function() { + this.countActive = 0; + var cols = [{ + name: "name", + cell: "string", + label: localization.tt("lbl.name"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryName') + }, { + name: "id", + cell: "string", + label: localization.tt("lbl.id"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryId') + }, { + name: "owner", + cell: "string", + label: localization.tt("lbl.owner"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryOwner') + }, { + name: "status", + cell: "string", + label: localization.tt("lbl.status"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryStatus') + }, { + name: "uptime", + cell: "string", + label: localization.tt("lbl.uptime"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryUptime') + }, { + name: "workersTotal", + cell: "string", + label: "# "+localization.tt("lbl.workers"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryWorkers') + }, { + name: "executorsTotal", + cell: "string", + label: "# "+localization.tt("lbl.executors"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryExecutors') + }, { + name: "tasksTotal", + cell: "string", + label: "# "+localization.tt("lbl.tasks"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryTasks') + }, { + name: "schedulerInfo", + cell: "string", + label: localization.tt("lbl.schedulerInfo"), + hasTooltip: true, + tooltipText: localization.tt('msg.topologySummaryScheduler') + }]; + return cols; + }, + + showSummaryTable: function(id) { + var object = _.findWhere(this.summaryArr, { + window: id + }); + if(_.isNull(object) || _.isUndefined(object)){ + object = {}; + object.emitted = 0; + object.transferred = 0; + object.completeLatency = 0; + object.acked = 0; + object.failed = 0; + object.window = id; + } + this.ui.topologySummary.html(this.summaryTemplate(object)); + }, + + evActivateTopology: function() { + var that = this; + bootbox.confirm({ + message: localization.tt('dialogMsg.activateTopologyMsg'), + buttons: { + confirm: { + label: localization.tt('btn.yes'), + className: "btn-success", + }, + cancel: { + label: localization.tt('btn.no'), + className: "btn-default", + } + }, + callback: function(result){ + if(result){ + that.model.activateTopology({ + id: that.model.get('id'), + success: function(model, response, options){ + Utils.notifySuccess(localization.tt('dialogMsg.topologyActivateSuccessfully')); + that.fetchData(that.model.get('id'), that.systemBoltFlag, that.windowTimeFrame); + }, + error: function(model, response, options){ + Utils.notifyError(model.statusText); + } + }); + } + } + }); + + }, + evDeactivateTopology: function() { + var that = this; + bootbox.confirm({ + message: localization.tt('dialogMsg.deactivateTopologyMsg'), + buttons: { + confirm: { + label: localization.tt('btn.yes'), + className: "btn-success", + }, + cancel: { + label: localization.tt('btn.no'), + className: "btn-default", + } + }, + callback: function(result){ + if(result){ + that.model.deactivateTopology({ + id: that.model.get('id'), + success: function(model, response, options){ + Utils.notifySuccess(localization.tt('dialogMsg.topologyDeactivateSuccessfully')); + that.fetchData(that.model.get('id'), that.systemBoltFlag, that.windowTimeFrame); + }, + error: function(model, response, options){ + Utils.notifyError(model.statusText); + } + }); + } + } + }); + }, + evRebalanceTopology: function() { + var that = this; + if(this.view){ + this.onDialogClosed(); + } + require(['views/Topology/RebalanceForm'], function(rebalanceForm){ + that.view = new rebalanceForm({ + spoutCollection : that.spoutsCollection, + boltCollection: that.boltsCollection + }); + that.view.render(); + + bootbox.dialog({ + message: that.view.$el, + title: localization.tt('lbl.rebalanceTopology'), + 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 err = that.view.validate(); + if(_.isEmpty(err)){ + that.rebalanceTopology(); + } else return false; + } + } + } + }); + }); + }, + rebalanceTopology: function(){ + var that = this, + attr = this.view.getValue(), + obj = {"rebalanceOptions":{}}; + + if(!_.isUndefined(attr.workers) && !_.isNull(attr.workers)){ + obj.rebalanceOptions.numWorkers = attr.workers; + } + + var spoutBoltObj = {}; + for(var key in attr){ + if(!_.isEqual(key,'workers') && !_.isEqual(key,'waitTime')){ + if(!_.isNull(attr[key])){ + spoutBoltObj[key] = attr[key]; + } + } + } + + if(_.keys(spoutBoltObj).length){ + obj.rebalanceOptions.executors = spoutBoltObj; + } + + $.ajax({ + url: Globals.baseURL + '/api/v1/topology/' + that.model.get('id') + '/rebalance/' + attr.waitTime, + data: (_.keys(obj.rebalanceOptions).length) ? JSON.stringify(obj) : null, + cache: false, + contentType: 'application/json', + type: 'POST', + success: function(model, response, options){ + if(!_.isUndefined(model.error)){ + Utils.notifyError(model.error); + } else { + Utils.notifySuccess(localization.tt('dialogMsg.topologyRebalanceSuccessfully')); + that.fetchData(that.model.get('id'), that.systemBoltFlag, that.windowTimeFrame); + } + }, + error: function(model, response, options){ + Utils.notifyError(model.statusText); + } + }); + }, + evKillTopology: function() { + var that = this; + bootbox.prompt({ + title: localization.tt('dialogMsg.killTopologyMsg'), + value: "30", + buttons: { + confirm: { + label: localization.tt('btn.yes'), + className: "btn-success", + }, + cancel: { + label: localization.tt('btn.no'), + className: "btn-default", + } + }, + callback: function(result) { + if(result != null){ + that.model.killTopology({ + id: that.model.get('id'), + waitTime: result, + success: function(model, response, options){ + Utils.notifySuccess(localization.tt('dialogMsg.topologyKilledSuccessfully')); + that.fetchData(that.model.get('id'), that.systemBoltFlag, that.windowTimeFrame); + }, + error: function(model, response, options){ + Utils.notifyError(model.statusText); + } + }); + } + } + }); + }, + onDialogClosed: function() { + if (this.view) { + this.view.close(); + this.view.remove(); + this.view = null; + } + }, + openAllTables: function(){ + console.log("Open All !!"); + }, + evSysBoltToggle: function(e){ + this.systemBoltFlag = $(e.currentTarget).is(':checked'); + this.fetchData(this.model.get('id'), this.systemBoltFlag, this.windowTimeFrame); + }, + + getSpoutColumns: function() { + var cols = [{ + name: "spoutId", + cell: "string", + label: localization.tt("lbl.id"), + sortable: true, + hasTooltip: true, + tooltipText: localization.tt('msg.spoutId') + }, + { + name: "executors", + cell: "string", + label: localization.tt("lbl.executors"), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutExecutors'), + sortable: true + }, + { + name: "tasks", + cell: "string", + label: localization.tt("lbl.tasks"), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutTask'), + sortable: true, + }, + { + name: "emitted", + cell: "string", + label: localization.tt("lbl.emitted"), + hasTooltip: true, + tooltipText: localization.tt('msg.emitted'), + sortable: true + }, + { + name: "transferred", + cell: "string", + label: localization.tt("lbl.transferred"), + hasTooltip: true, + tooltipText: localization.tt('msg.transferred'), + sortable: true + }, + { + name: "completeLatency", + cell: "string", + label: localization.tt("lbl.completeLatency"), + hasTooltip: true, + tooltipText: localization.tt('msg.completeLatency'), + sortable: true + }, + { + name: "acked", + cell: "string", + label: localization.tt("lbl.acked"), + hasTooltip: true, + tooltipText: localization.tt('msg.acked'), + sortable: true + }, + { + name: "failed", + cell: "string", + label: localization.tt("lbl.failed"), + hasTooltip: true, + tooltipText: localization.tt('msg.failed'), + sortable: true + } + ]; + return cols; + }, + + getBoltColumns: function() { + var cols = [{ + name: "boltId", + cell: "string", + label: localization.tt('lbl.id'), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutId'), + sortable: true + }, { + name: "executors", + cell: "string", + label: localization.tt('lbl.executors'), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutExecutors'), + }, { + name: "tasks", + cell: "string", + label: localization.tt('lbl.tasks'), + hasTooltip: true, + tooltipText: localization.tt('msg.spoutTasks'), + }, { + name: "emitted", + cell: "string", + label: localization.tt('lbl.emitted'), + hasTooltip: true, + tooltipText: localization.tt('msg.emitted'), + }, { + name: "transferred", + cell: "string", + label: localization.tt('lbl.transferred'), + hasTooltip: true, + tooltipText: localization.tt('msg.transferred'), + }, { + name: "capacity", + cell: "string", + label: localization.tt('lbl.capacity'), + formatter: _.extend({}, Backgrid.CellFormatter.prototype, { + fromRaw: function(rawValue, model) { + if (model) { + return (parseFloat(model.attributes.capacity) < 1 ? " < 1%" : " "+model.get('capacity')+" %"); + } + } + }), + hasTooltip: true, + tooltipText: localization.tt('msg.boltCapacity'), + }, { + name: "executeLatency", + cell: "string", + label: localization.tt('lbl.executeLatency'), + hasTooltip: true, + tooltipText: localization.tt('msg.boltExecuteLatency'), + }, { + name: "executed", + cell: "string", + label: localization.tt('lbl.executed'), + hasTooltip: true, + tooltipText: localization.tt('msg.boltExected'), + }, { + name: "processLatency", + cell: "string", + label: localization.tt('lbl.processLatency'), + hasTooltip: true, + tooltipText: localization.tt('msg.boltProcessLatency'), + }, { + name: "acked", + cell: "string", + label: localization.tt('lbl.acked'), + hasTooltip: true, + tooltipText: localization.tt('msg.boltAcked'), + }]; + return cols; + }, + + showBreadCrumbs: function(){ + vent.trigger('Breadcrumb:Show', (this.model.has('name')) ? this.model.get('name') : 'No-Name'); + }, + + getTopoConfigColumns: function() { + + var cols = [ + + { + name: "key", + cell: "string", + label: localization.tt('lbl.key'), + sortable: true + }, { + name: "value", + cell: "string", + label: localization.tt('lbl.value'), + } + ]; + return cols; + }, + + startPollingAction: function(id){ + var that = this; + setTimeout(function(){ + if(_.isEqual(typeof that.ui.BoltsSummaryDetails, "object")){ + that.fetchData(id, that.systemBoltFlag, that.windowTimeFrame); + } + }, Globals.settings.refreshInterval); + } + + }); + return masterView; +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/cd6398a1/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyForm.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyForm.js b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyForm.js new file mode 100644 index 0000000..d08e353 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyForm.js @@ -0,0 +1,102 @@ +/** +* 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(['utils/LangSupport', + 'utils/Globals', + 'hbs!tmpl/topology/topologyForm', + 'backbone.forms' + ], function (localization, Globals, tmpl) { + 'use strict'; + + // var tmpl = ; + var TopologyForm = Backbone.Form.extend({ + + template: tmpl, + + initialize: function (options) { + Backbone.Form.prototype.initialize.call(this, options); + this.bindEvents(); + }, + + bindEvents: function () { + console.log('Binding Events Here !!'); + }, + + schema: function () { + return { + name: { + type: 'Text', + title: localization.tt('lbl.name')+'*', + editorClass : 'form-control', + validators: ['required'] + }, + jar: { + type: 'Fileupload', + title: localization.tt('lbl.jar')+'*', + validators: ['required'] + }, + // nimbusHostname: { + // type: 'Select', + // title: localization.tt('lbl.nimbusHostname')+'*', + // options: [{ + // val: '', + // label: '--' + // }, + // { + // val: '1', + // label: 'Hostname 1' + // }, { + // val: '2', + // label: 'Hostname 2' + // }, { + // val: '3', + // label: 'Hostname 3' + // }], + // editorClass : 'form-control', + // validators: ['required'] + // }, + topologyClass: { + type: 'Text', + title: localization.tt('lbl.topologyClass')+'*', + editorClass : 'form-control', + validators: ['required'] + }, + arguments: { + type: 'Text', + title: localization.tt('lbl.arguments'), + editorClass : 'form-control', + // validators: ['required'] + } + }; + }, + + // render: function (options) { + // Backbone.Form.prototype.render.call(this, options); + // }, + + getData: function () { + return this.getValue(); + }, + + close: function () { + console.log('Closing form view'); + } + }); + + return TopologyForm; +}); \ No newline at end of file
