http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/modules/Table/Pagination.jsx ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/modules/Table/Pagination.jsx b/contrib/views/storm/src/main/resources/scripts/modules/Table/Pagination.jsx new file mode 100644 index 0000000..41a763c --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/modules/Table/Pagination.jsx @@ -0,0 +1,158 @@ +/** + 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(['react', 'utils/Globals'], function(React, Globals){ + 'use strict'; + return React.createClass({ + displayName: 'Pagination', + + getInitialState: function(){ + this.props.collection.on('reset', function(data){ + this.setState({'collection': data}); + }.bind(this)); + return { + collection: this.props.collection + }; + }, + /** + * Next page button being clicked + */ + nextPage: function(e) { + e.preventDefault(); + this.props.collection.getNextPage(this.props.collection.state.currentPage); + }, + /** + * Previous page button being clicked + */ + previousPage: function(e) { + e.preventDefault(); + this.props.collection.getPreviousPage(this.props.collection.state.currentPage); + }, + /** + * Change page being clicked + * @param {Event} e Event of the page number being clicked + */ + changePage: function(e) { + e.preventDefault(); + var pageNumber = +e.currentTarget.getAttribute('data-page'); + this.props.collection.getParticularPage(pageNumber); + }, + /** + * Render function for the next page button. + * If the current page is the last then it shouldn't render a clickable next page + */ + renderNext: function() { + if(this.props.collection.state.currentPage < this.props.collection.state.totalPages){ + return (<li><a href="javascript: void(0);" ref="nextPage" onClick={this.nextPage}>»</a></li>); + } else { + return (<li className="disabled"><a href="javascript: void 0;">»</a></li>); + } + }, + /** + * Render functon for the pages + * If the number of maximumPages is exceeded by the number of pages then that must be handled with an ellipsis + * If the page is active then it should have the active class + * + */ + renderPages: function(){ + var pages = []; + var starterPage = 1; + if(this.props.collection.state.currentPage >= 4) { + starterPage = this.props.collection.state.currentPage - 1; + } + var page = 1; + if(!this.props.maximumPages || this.props.maximumPages > this.props.collection.state.totalPages) { + for(page = 1; page <= this.props.collection.state.totalPages; page++){ + if(page !== this.props.collection.state.currentPage) { + pages.push(<li key={page}><a href="javascript: void 0;" onClick={this.changePage} data-page={page}>{page}</a></li>); + } else { + pages.push(<li key={page} className="active"><a href="javascript: void 0;" >{page}</a></li>); + + } + } + } else { + if(this.props.collection.state.currentPage >= 4) { + pages.push(<li key={1}><a href="javascript: void 0;" onClick={this.changePage} data-page={1} >{1}</a></li>); + pages.push(<li key="leftellips" className="disabled"><a href="javascript: void 0;">…</a></li>); + + } + for(page = starterPage; page <= this.props.collection.state.totalPages; ++page) { + if((starterPage + this.props.maximumPages) < page && (page + this.props.maximumPages) < this.props.collection.state.totalPages) { + pages.push(<li key={'ellips'} className="disabled"><a href="javascript: void 0;">…</a></li>); + pages.push(<li key={'collection.state.totalPages'}><a href="javascript: void 0;" onClick={this.changePage} data-page={this.props.collection.state.totalPages} className="">{this.props.collection.state.totalPages}</a></li>); + break; + } else if (page !== this.props.collection.state.currentPage){ + pages.push(<li key={page}><a href="javascript: void 0;" onClick={this.changePage} data-page={page} className="">{page}</a></li>); + } else { + pages.push(<li key={page} className="active"><a href="javascript: void 0;" >{page}</a></li>); + + } + } + } + return pages; + + }, + /** + * Render function for the previous page button. + * If the current page is the first then it shouldn't render a clickable previous page + */ + renderPrevious : function() { + if(this.props.collection.state.currentPage > 1){ + return (<li className=""><a href="javascript: void 0;" ref="prevPage" onClick={this.previousPage}>«</a></li>); + }else { + return (<li className="disabled"><a href="javascript: void 0;" >«</a></li>); + } + }, + renderNumber: function(){ + var startNumber, endNumber; + if(this.props.collection.state.currentPage > 1){ + startNumber = ((this.props.collection.state.currentPage - 1) * Globals.settings.PAGE_SIZE) + 1; + endNumber = startNumber + Globals.settings.PAGE_SIZE - 1; + if(endNumber > this.props.collection.state.totalRecords){ + endNumber = this.props.collection.state.totalRecords; + } + } else { + startNumber = 1; + if(this.props.collection.state.totalRecords){ + endNumber = (this.props.collection.state.totalRecords > Globals.settings.PAGE_SIZE ? Globals.settings.PAGE_SIZE : this.props.collection.state.totalRecords); + } else { + startNumber = 0; + endNumber = 0; + } + } + return ( + <span className="pull-left">Showing {startNumber} to {endNumber} of {this.props.collection.state.totalRecords || 0} entries.</span> + ); + }, + + render: function () { + var next = this.renderNext(); + var pages = this.renderPages(); + var previous = this.renderPrevious(); + var number = this.renderNumber(); + return(<div className="clearfix"> + {number} + <ul className="pagination pagination-sm pull-right no-margin"> + {previous} + {pages} + {next} + </ul> + </div>); + } + }); +}); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/modules/Vent.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/modules/Vent.js b/contrib/views/storm/src/main/resources/scripts/modules/Vent.js deleted file mode 100644 index eebd6d7..0000000 --- a/contrib/views/storm/src/main/resources/scripts/modules/Vent.js +++ /dev/null @@ -1,22 +0,0 @@ -/** -* 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(['backbone.wreqr'], function (Wreqr) { - "use strict"; - return new Wreqr.EventAggregator(); -}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/router/Router.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/router/Router.js b/contrib/views/storm/src/main/resources/scripts/router/Router.js index 98007e7..24fc1e0 100644 --- a/contrib/views/storm/src/main/resources/scripts/router/Router.js +++ b/contrib/views/storm/src/main/resources/scripts/router/Router.js @@ -1,97 +1,99 @@ /** -* 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 + 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 + 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. + 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([ - 'jquery', - 'underscore', + 'require', 'backbone', - 'utils/Utils', - 'App' -], function($, _, Backbone, Utils, App) { + 'react', + 'react-dom', + 'utils/Utils' +], function(require, Backbone, React, ReactDOM, Utils) { + 'use strict'; + var rRender; var AppRouter = Backbone.Router.extend({ routes: { - // Define some URL routes - "": 'topologySummaryAction', - "!/topology": 'topologySummaryAction', - "!/topology/:id": 'topologyDetailAction', - - // Default - '*actions': 'defaultAction' + '' : 'dashboardAction', + '!/dashboard' : 'dashboardAction', + '!/topology' : 'topologyAction', + '!/topology/:id' : 'topologyDetailsAction', + '!/topology/:id/component/:name' : 'componentDetailsAction', + '!/nimbus' : 'nimbusAction', + '!/supervisor' : 'supervisorAction', + '*actions' : 'defaultAction' }, - initialize: function() { + App.baseURL = Utils.getStormHostDetails(); + // App.baseURL = 'http://c6502:8744'; this.showRegions(); - this.bindRegions(); - this.listenTo(this, "route", this.postRouteExecute, this); }, - - showRegions: function () { - require(['views/site/Header'], function (HeaderView) { - App.rHeader.show(new HeaderView()); - }); + showRegions: function() { + this.renderFooter(); }, - - bindRegions: function () { - var that = this; - require(['modules/Vent'], function(vent){ - vent.on('Region:showTopologySection', function(){ - App.rCluster.$el.removeClass('active').hide(); - App.rTopology.$el.addClass('active').show(); - if(App.rTopology.$el.children().hasClass('topologyDetailView')){ - that.topologyDetailAction(App.rTopology.currentView.model.get('id')); - } else { - that.topologySummaryAction(); - } - }); - - vent.on('Region:showClusterSection', function(){ - require(['views/Cluster/ClusterSummary'], function(ClusterSummaryView){ - App.rCluster.show(new ClusterSummaryView()); - }); - App.rTopology.$el.removeClass('active').hide(); - App.rCluster.$el.addClass('active').show(); - vent.trigger('Breadcrumb:Hide'); - }); - + renderFooter: function(){ + require(['jsx!views/Footer'], function(Footer){ + ReactDOM.render(React.createElement(Footer), App.Footer); }); }, + execute: function(callback, args) { + this.preRouteExecute(); + if (callback) callback.apply(this, args); + this.postRouteExecute(); + }, + preRouteExecute: function() {}, + postRouteExecute: function(name, args) {}, /** * Define route handlers here */ - topologySummaryAction: function() { - require(['views/Topology/TopologySummary'],function(TopologySummaryView){ - App.rTopology.show(new TopologySummaryView()); - }); + + dashboardAction: function(){ + require(['jsx!views/Dashboard'], function(DashboardView){ + ReactDOM.render(React.createElement(DashboardView), App.Container); + }); }, - - topologyDetailAction: function(id) { - require(['views/Topology/TopologyDetail'], function(TopologyDetailView){ - App.rTopology.show(new TopologyDetailView({ - id: id - })); + topologyAction: function(){ + require(['jsx!views/TopologyListingView'], function(TopologyListingView){ + ReactDOM.render(React.createElement(TopologyListingView), App.Container); + }); + }, + topologyDetailsAction: function(id){ + require(['jsx!views/TopologyDetailView'], function(TopologyDetailView){ + ReactDOM.render(React.createElement(TopologyDetailView, Object.assign({}, this.props, {id: id})), App.Container); + }.bind(this)); + }, + componentDetailsAction: function(id, name){ + require(['jsx!views/ComponentDetailView'], function(ComponentDetailView){ + ReactDOM.render(React.createElement(ComponentDetailView, Object.assign({}, this.props, {id: id, name: name})), App.Container); + }.bind(this)); + }, + nimbusAction: function(){ + require(['jsx!views/NimbusSummaryView'], function(NimbusSummaryView){ + ReactDOM.render(React.createElement(NimbusSummaryView), App.Container); + }); + }, + supervisorAction: function(){ + require(['jsx!views/SupervisorSummaryView'], function(SupervisorSummaryView){ + ReactDOM.render(React.createElement(SupervisorSummaryView), App.Container); }); }, - defaultAction: function(actions) { - // We have no matching route, lets just log what the URL was - console.log('No route:', actions); - } + throw new Error("No such route found in the application: "+actions); + }, }); return AppRouter; http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/utils/Globals.js ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/utils/Globals.js b/contrib/views/storm/src/main/resources/scripts/utils/Globals.js index bfbb873..c28d45f 100644 --- a/contrib/views/storm/src/main/resources/scripts/utils/Globals.js +++ b/contrib/views/storm/src/main/resources/scripts/utils/Globals.js @@ -1,30 +1,30 @@ /** -* 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 + 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 + 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. + 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', 'App'], function (require, App) { +define(['require'], function (require) { 'use strict'; + var Globals = {}; - var Globals = {}; + Globals.baseURL = App.baseURL; - Globals.baseURL = App.baseUrl; + Globals.settings = { + PAGE_SIZE: 25 + }; - Globals.settings = {}; - Globals.settings.refreshInterval = 60000; - - return Globals; + return Globals; }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/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 deleted file mode 100644 index 79822c7..0000000 --- a/contrib/views/storm/src/main/resources/scripts/utils/LangSupport.js +++ /dev/null @@ -1,116 +0,0 @@ -/** -* 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/529ef7f7/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 index 251e2d4..7bb6b3f 100644 --- a/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js +++ b/contrib/views/storm/src/main/resources/scripts/utils/Overrides.js @@ -1,299 +1,33 @@ /** - * 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); - }; - - Backbone.Form.editors.RangeSlider = Backbone.Form.editors.Base.extend({ - ui: { - - }, - events: { - 'change #from': 'evChange', - }, - - initialize: function(options) { - this.options = options; - Backbone.Form.editors.Base.prototype.initialize.call(this, options); - this.template = _.template('<div id="scoreSlider" style="width: 50%; float: left; margin-top: 5px;" class="ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all" aria-disabled="false"><div class="ui-slider-range ui-widget-header ui-corner-all" style="left: 0%; width: 100%; "></div><a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left: 0%; "></a></div><input type="number" id="from" class="input-mini" style="float:left; width: 60px; margin-left: 15px;" placeholder="0"/><div id="sliderLegend" style="width: 50%"><label id="startLabel" style="float: left;">0</label><label id="endLabel" style="float: right;">0</label></div>'); - }, - - evChange: function(e) { - var val = e.currentTarget.value; - if (val == '') { - val = '0'; - } - - var sanitized = val.replace(/[^0-9]/g, ''); - - if (_.isNumber(parseInt(sanitized, 10))) { - if (sanitized < this.options.schema.options.max) { - $(e.currentTarget).val(sanitized); - this.$('#scoreSlider').slider('value', sanitized); - } else { - $(e.currentTarget).val(this.options.schema.options.max); - this.$('#scoreSlider').slider('value', this.options.schema.options.max); - } - } - - }, - - /** - * Adds the editor to the DOM - */ - render: function() { - this.$el.html(this.template); - this.setupSlider(this.options.schema.options); - if (this.value) - this.setValue(this.value); - return this; - }, - - getValue: function() { - return { - min: this.$("#from").val(), - }; - }, - - setValue: function(value) { - this.$("#from").val(value); - return this.$('#scoreSlider').slider('value'); - }, - setupSlider: function(options) { - var that = this; - var minVal = options && options.min ? options.min : 0, - maxVal = options && options.max ? options.max : 0; - this.$('#scoreSlider').slider({ - range: "max", - min: minVal, - max: maxVal, - value: this.value, - slide: function(event, ui) { - that.$("#from").val(ui.value); - } - }); - this.$('#startLabel').text(minVal); - this.$('#endLabel').text(maxVal); - this.$('#from').attr("min", minVal); - this.$('#from').attr("max", maxVal); - if (this.options.schema.minEditorClass) - this.$('#from').addClass(this.options.schema.minEditorClass); - } - }); - + 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(['backbone'], function(Backbone){ + 'use strict'; + + // $('.loader').hide(); + + Backbone.ajax = function() { + if(!arguments[0].data){ + 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); + }; }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/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 deleted file mode 100644 index d827601..0000000 --- a/contrib/views/storm/src/main/resources/scripts/utils/TableLayout.js +++ /dev/null @@ -1,106 +0,0 @@ -/** -* 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/529ef7f7/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 index 72080d5..56a42a6 100644 --- a/contrib/views/storm/src/main/resources/scripts/utils/Utils.js +++ b/contrib/views/storm/src/main/resources/scripts/utils/Utils.js @@ -1,133 +1,172 @@ /** -* 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 + 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 + 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. + 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'; +define(['require', + 'react', + 'react-dom', + 'bootbox', + 'bootstrap', + 'bootstrap-notify'], function(require, React, ReactDOM, bootbox) { + 'use strict'; + var Utils = {}; - var Utils = {}; - - Utils.defaultErrorHandler = function(model, error) { - if (error.status == 401) { - console.log("ERROR 401 occured."); - } - }; + 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 == "") { + console.log("Error detected while fetching storm hostname and port number"); + } 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 { + console.log("Error detected while fetching storm hostname and port number"); + } + } else { + console.log("Error detected while fetching storm hostname and port number"); + } + } + }, + error: function(res) { + console.log("Error detected while fetching storm hostname and port number"); + } + }); + } + }); + } else { + console.log("Currently, no service is configured in ambari"); + } + }, + error: function(error) { + console.log("Error detected while fetching storm hostname and port number"); + } + }); + return url; + }; - 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.ArrayToCollection = function(array, collection){ + if(array.length){ + array.map(function(obj){ + collection.add(new Backbone.Model(obj)); + }); + } + return collection; + }; - 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.ConfirmDialog = function(message, title, successCallback, cancelCallback) { + bootbox.dialog({ + message: message, + title: title, + className: 'confirmation-dialog', + buttons: { + cancel: { + label: 'No', + className: 'btn-default btn-small', + callback: cancelCallback ? cancelCallback : function(){} + }, + success: { + label: 'Yes', + className: 'btn-success btn-small', + callback: successCallback + } + } + }); + }; - 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.notifyError = function(message) { + $.notify({ + icon: 'fa fa-warning', + message: message + },{ + type: 'danger', + allow_dismiss: true, + animate: { + enter: 'animated fadeInDown', + exit: 'animated fadeOutUp' + } + }); + }; + Utils.notifySuccess = function(message) { + $.notify({ + icon: 'fa fa-check', + message: message + },{ + type: 'success', + allow_dismiss: true, + animate: { + enter: 'animated fadeInDown', + exit: 'animated fadeOutUp' + } + }); + }; - 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.notifyInfo = function(message) { + $.notify({ + icon: 'fa fa-info', + message: message + },{ + type: 'info', + allow_dismiss: true, + animate: { + enter: 'animated fadeInDown', + exit: 'animated fadeOutUp' + } + }); + }; - 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')); - } - }); + Utils.notifyWarning = function(message) { + $.notify({ + icon: 'fa fa-warning', + message: message + },{ + type: 'warning', + allow_dismiss: true, + animate: { + enter: 'animated fadeInDown', + exit: 'animated fadeOutUp' } - }); - } 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 + return Utils; +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/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 deleted file mode 100644 index 540f2f6..0000000 --- a/contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js +++ /dev/null @@ -1,353 +0,0 @@ -/** -* 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-plus-square").removeClass("fa-plus-square").addClass("fa-minus-square"); - }).on('hidden.bs.collapse', function() { - $(this).parent().find(".fa-minus-square").removeClass("fa-minus-square").addClass("fa-plus-square"); - }); - - }, - 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) { - vent.trigger('LastUpdateRefresh'); - that.clusterCollection.trigger('sync', that.clusterCollection); - if (model) { - that.clusterCollection.reset(model); - } - }, - error: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - that.clusterCollection.trigger('error', that.clusterCollection); - 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) { - vent.trigger('LastUpdateRefresh'); - 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); - } - }, - error: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - that.sprCollection.trigger('error', that.sprCollection); - Utils.notifyError(response.statusText); - } - }); - }, - - getNimbusConfig: function(model) { - var that = this; - this.nimbusConfigCollection.trigger('request', this.nimbusConfigCollection); - model.fetch({ - success: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - 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); - } - }, - error: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - that.nimbusConfigCollection.trigger('error', that.nimbusConfigCollection); - Utils.notifyError(response.statusText); - } - }); - }, - - getNimbusSummary: function(model){ - var that = this; - this.nbsCollection.trigger('request', this.nbsCollection); - model.fetch({ - success: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - 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); - } - }, - error: function(model, response, options) { - vent.trigger('LastUpdateRefresh'); - that.nbsCollection.trigger('error', that.nbsCollection); - 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; - } - - }); - return ClusterSummaryTableLayout; -}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/views/ComponentDetailView.jsx ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/ComponentDetailView.jsx b/contrib/views/storm/src/main/resources/scripts/views/ComponentDetailView.jsx new file mode 100644 index 0000000..14f7527 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/ComponentDetailView.jsx @@ -0,0 +1,507 @@ +/** + 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([ + 'jsx!components/Table', + 'jsx!modules/Table/Pagination', + 'react', + 'react-dom', + 'collections/BaseCollection', + 'models/VTopology', + 'jsx!components/Breadcrumbs', + 'jsx!views/ProfilingView', + 'utils/Utils', + 'bootbox', + 'bootstrap', + 'bootstrap-switch' + ],function(Table, Pagination, React, ReactDOM, BaseCollection, VTopology, Breadcrumbs, ProfilingView, Utils, bootbox){ + 'use strict'; + + return React.createClass({ + displayName: 'ComponentDetailView', + getInitialState: function(){ + this.model = new VTopology({'id': this.props.id}); + this.systemFlag = (this.props.name.startsWith('__')) ? true : false; + this.windowSize = ':all-time'; + this.initializeData(); + return { + componentObj: {}, + profilingModalOpen: false + }; + }, + componentWillMount: function(){ + $('.loader').show(); + }, + componentWillUpdate: function(){ + $('.loader').show(); + $('#collapse-input').off('hidden.bs.collapse').off('shown.bs.collapse'); + $('#collapse-output').off('hidden.bs.collapse').off('shown.bs.collapse'); + $('#collapse-executor').off('hidden.bs.collapse').off('shown.bs.collapse'); + $('#collapse-error').off('hidden.bs.collapse').off('shown.bs.collapse'); + }, + componentDidMount: function(){ + $(".boot-switch.systemSum").bootstrapSwitch({ + size: 'small', + onSwitchChange: function(event, state){ + this.systemFlag = state; + this.initializeData(); + }.bind(this) + }); + + $(".boot-switch.debug").bootstrapSwitch({ + size: 'small', + onSwitchChange: function(event, state){ + this.debugAction(state); + }.bind(this) + }); + $('.loader').hide(); + }, + componentDidUpdate: function(){ + $('#collapse-input').on('hidden.bs.collapse', function () { + $("#input-box").toggleClass("fa-compress fa-expand"); + }).on('shown.bs.collapse', function() { + $("#input-box").toggleClass("fa-compress fa-expand"); + }); + + $('#collapse-output').on('hidden.bs.collapse', function () { + $("#output-box").toggleClass("fa-compress fa-expand"); + }).on('shown.bs.collapse', function() { + $("#output-box").toggleClass("fa-compress fa-expand"); + }); + + $('#collapse-executor').on('hidden.bs.collapse', function () { + $("#executor-box").toggleClass("fa-compress fa-expand"); + }).on('shown.bs.collapse', function() { + $("#executor-box").toggleClass("fa-compress fa-expand"); + }); + + $('#collapse-error').on('hidden.bs.collapse', function () { + $("#error-box").toggleClass("fa-compress fa-expand"); + }).on('shown.bs.collapse', function() { + $("#error-box").toggleClass("fa-compress fa-expand"); + }); + $('#modal-profiling').on('hidden.bs.modal', function (e) { + this.initializeData(); + this.setState({"profilingModalOpen":false}); + }.bind(this)); + if(this.state.profilingModalOpen){ + $('#modal-profiling').modal("show"); + } + $('.loader').hide(); + }, + initializeData: function(){ + this.model.getComponent({ + id: this.props.id, + name: this.props.name, + window: this.windowSize, + sys: this.systemFlag, + success: function(model, response){ + if(response.error){ + Utils.notifyError(response.error); + } else { + this.setState({"componentObj": model}); + } + }.bind(this), + error: function(model, response, options){ + Utils.notifyError("Error occured in fetching topology component data."); + } + }); + }, + renderWindowOptions: function(){ + var arr = this.state.componentObj.spoutSummary || this.state.componentObj.boltStats; + if(arr){ + return arr.map(function(object, i){ + return ( <option key={i} value={object.window}>{object.windowPretty}</option> ); + }); + } else { + return null; + } + }, + handleWindowChange: function(e){ + this.windowSize = e.currentTarget.value; + this.initializeData(); + }, + getLinks: function() { + var links = [ + {link: '#!/dashboard', title: 'Dashboard'}, + {link: '#!/topology', title: 'Topology Listing'}, + {link: '#!/topology/'+this.state.componentObj.topologyId, title: this.state.componentObj.name || ""}, + {link: 'javascript:void(0);', title: this.state.componentObj.id || ""} + ]; + return links; + }, + renderStatsRow: function(){ + var spoutFlag = (this.state.componentObj.componentType === 'spout' ? true: false); + var statsArr = this.state.componentObj.spoutSummary || this.state.componentObj.boltStats; + if(statsArr){ + return statsArr.map(function(stats, i){ + return ( + <tr key={i}> + <td>{stats.windowPretty}</td> + <td>{stats.emitted}</td> + <td>{stats.transferred}</td> + {spoutFlag ? <td>{stats.completeLatency}</td> : null} + {!spoutFlag ? <td>{stats.executeLatency}</td> : null} + {!spoutFlag ? <td>{stats.executed}</td> : null} + {!spoutFlag ? <td>{stats.processLatency}</td> : null} + <td>{stats.acked}</td> + <td>{stats.failed}</td> + </tr> + ); + }); + } + }, + renderAccordion: function(type, header, searchField, searchCb, collection, emptyText, columns, toggleCb){ + return ( + <div className="box"> + <div className="box-header" data-toggle="collapse" data-target={"#collapse-"+type} aria-expanded="false" aria-controls={"collapse-"+type}> + <h4>{header} ( {this.state.componentObj.windowHint} )</h4> + <h4 className="box-control"> + <a href="javascript:void(0);" className="primary"> + <i className="fa fa-compress" id={type+"-box"} onClick={toggleCb}></i> + </a> + </h4> + </div> + <div className="box-body collapse in" id={"collapse-"+type}> + <div className="input-group col-sm-4"> + <input type="text" onKeyUp={searchCb} className="form-control" placeholder={"Search by "+searchField} /> + <span className="input-group-btn"> + <button className="btn btn-primary" type="button"><i className="fa fa-search"></i></button> + </span> + </div> + <Table className="table table-striped" collection={collection} emptyText={emptyText} columns={columns()} /> + {type === 'error' ? <Pagination collection={collection} /> : null} + </div> + </div> + ); + }, + renderInputStats: function(){ + var inputCollection = Utils.ArrayToCollection(this.state.componentObj.inputStats, new BaseCollection()); + inputCollection.searchFields = ['component']; + var searchCb = function(e){ + var value = e.currentTarget.value; + inputCollection.search(value); + }; + var toggleCb = function(e){ + $("#collapse-input").collapse('toggle'); + } + return this.renderAccordion('input', 'Input Stats', 'component', searchCb, inputCollection, 'No input stats found !', this.getInputColumns, toggleCb); + }, + getInputColumns: function(){ + return [ + {name: 'component', title: 'Component', tooltip: 'The ID assigned to a the Component by the Topology.'}, + {name: 'stream', title: 'Stream', tooltip: 'The name of the Tuple stream given in the Topolgy, or "default" if none was given.'}, + {name: 'executeLatency', title: 'Execute Latency (ms)', tooltip: 'The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.'}, + {name: 'executed', title: 'Executed', tooltip: 'The number of incoming Tuples processed.'}, + {name: 'processLatency', title: 'Process Latency (ms)', tooltip: 'The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received.'}, + {name: 'acked', title: 'Acked', tooltip: 'The number of Tuples acknowledged by this Bolt.'}, + {name: 'failed', title: 'Failed', tooltip: 'The number of tuples Failed by this Bolt.'} + ]; + }, + renderOutputStats: function(){ + var outputCollection = Utils.ArrayToCollection(this.state.componentObj.outputStats, new BaseCollection()); + outputCollection.searchFields = ['stream']; + var searchCb = function(e){ + var value = e.currentTarget.value; + outputCollection.search(value); + }; + var toggleCb = function(e){ + $("#collapse-output").collapse('toggle'); + } + return this.renderAccordion('output', 'Output Stats', 'stream', searchCb, outputCollection, 'No output stats found !', this.getOutputColumns, toggleCb); + }, + getOutputColumns: function(){ + if(this.state.componentObj.componentType === 'spout'){ + return [ + {name: 'stream', title: 'Stream', tooltip: 'The name of the Tuple stream given in the Topolgy, or "default" if none was given.'}, + {name: 'emitted', title: 'Emitted', tooltip: 'The number of Tuples emitted.'}, + {name: 'transferred', title: 'Transferred', tooltip: 'The number of Tuples emitted that sent to one or more bolts.'}, + {name: 'completeLatency', title: 'Complete Latency (ms)', tooltip: 'The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.'}, + {name: 'acked', title: 'Acked', tooltip: 'The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.'}, + {name: 'failed', title: 'Failed', tooltip: 'The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done.'} + ]; + } else { + return [ + {name: 'stream', title: 'Stream', tooltip: 'The name of the Tuple stream given in the Topolgy, or "default" if none was given.'}, + {name: 'emitted', title: 'Emitted', tooltip: 'The number of Tuples emitted.'}, + {name: 'transferred', title: 'Transferred', tooltip: 'The number of Tuples emitted that sent to one or more bolts.'} + ]; + } + }, + renderExecutorStats: function(){ + var executorCollection = Utils.ArrayToCollection(this.state.componentObj.executorStats, new BaseCollection()); + executorCollection.searchFields = ['id']; + var searchCb = function(e){ + var value = e.currentTarget.value; + executorCollection.search(value); + }; + var toggleCb = function(e){ + $("#collapse-executor").collapse('toggle'); + } + return this.renderAccordion('executor', 'Executor Stats', 'id', searchCb, executorCollection, 'No executor stats found !', this.getExecutorColumns, toggleCb); + }, + getExecutorColumns: function(){ + var self = this; + if(this.state.componentObj.componentType === 'spout'){ + return [ + {name: 'id', title: 'Id', tooltip: 'The unique executor ID.'}, + {name: 'uptime', title: 'Uptime', tooltip: 'The length of time an Executor (thread) has been alive.'}, + {name: 'port', title: 'Host:Port', tooltip: 'The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.) Click on it to open the logviewer page for this Worker.', component: React.createClass({ + render: function(){ + return ( <a href={this.props.model.get('workerLogLink')} target="_blank"> {this.props.model.get('host')}:{this.props.model.get('port')} </a>); + } + })}, + {name: 'emitted', title: 'Emitted', tooltip: 'The number of Tuples emitted.'}, + {name: 'transferred', title: 'Transferred', tooltip: 'The number of Tuples emitted that sent to one or more bolts.'}, + {name: 'completeLatency', title: 'Complete Latency (ms)', tooltip: 'The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.'}, + {name: 'acked', title: 'Acked', tooltip: 'The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.'}, + {name: 'failed', title: 'Failed', tooltip: 'The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done.'}, + {name: 'workerLogLink', title: 'Dumps', component: React.createClass({ + render: function(){ + var link = this.props.model.get('workerLogLink'); + link = ""+link.split('/log')[0]+"/dumps/"+self.props.id+"/"+this.props.model.get('host')+":"+this.props.model.get('port'); + return (<a href={link} className="btn btn-primary btn-xs" target="_blank"><i className="fa fa-file-text"></i></a>); + } + })} + ]; + } else { + return [ + {name: 'id', title: 'Id', tooltip: 'The unique executor ID.'}, + {name: 'uptime', title: 'Uptime', tooltip: 'The length of time an Executor (thread) has been alive.'}, + {name: 'port', title: 'Host:Port', tooltip: 'The hostname reported by the remote host. (Note that this hostname is not the result of a reverse lookup at the Nimbus node.) Click on it to open the logviewer page for this Worker.', component: React.createClass({ + render: function(){ + return ( <a href={this.props.model.get('workerLogLink')} target="_blank"> {this.props.model.get('host')}:{this.props.model.get('port')} </a>); + } + })}, + {name: 'emitted', title: 'Emitted', tooltip: 'The number of Tuples emitted.'}, + {name: 'transferred', title: 'Transferred', tooltip: 'The number of Tuples emitted that sent to one or more bolts.'}, + {name: 'capacity', title: 'Capacity (last 10m)', tooltip: "If this is around 1.0, the corresponding Bolt is running as fast as it can, so you may want to increase the Bolt's parallelism. This is (number executed * average execute latency) / measurement time."}, + {name: 'executeLatency', title: 'Execute Latency (ms)', tooltip: 'The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.'}, + {name: 'executed', title: 'Executed', tooltip: 'The number of incoming Tuples processed.'}, + {name: 'processLatency', title: 'Process Latency (ms)', tooltip: 'The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received.'}, + {name: 'acked', title: 'Acked', tooltip: 'The number of Tuples acknowledged by this Bolt.'}, + {name: 'failed', title: 'Failed', tooltip: 'The number of tuples Failed by this Bolt.'}, + {name: 'workerLogLink', title: 'Dumps', component: React.createClass({ + render: function(){ + var link = this.props.model.get('workerLogLink'); + link = ""+link.split('/log')[0]+"/dumps/"+self.props.id+"/"+this.props.model.get('host')+":"+this.props.model.get('port'); + return (<a href={link} className="btn btn-primary btn-xs" target="_blank"><i className="fa fa-file-text"></i></a>); + } + })} + ]; + } + }, + renderErrorStats: function(){ + var errorCollection = Utils.ArrayToCollection(this.state.componentObj.componentErrors, new BaseCollection()); + errorCollection.searchFields = ['error']; + var searchCb = function(e){ + var value = e.currentTarget.value; + errorCollection.search(value); + }; + var toggleCb = function(e){ + $("#collapse-error").collapse('toggle'); + } + return this.renderAccordion('error', 'Error Stats', 'error', searchCb, errorCollection, 'No errors found !', this.getErrorColumns, toggleCb); + }, + getErrorColumns: function(){ + return [ + {name: 'errorTime', title: 'Time', component: React.createClass({ + render: function(){ + if(this.props.model.get('errorTime') != 0) { + var d = new Date(this.props.model.get('errorTime')), + date = d.toLocaleDateString() + ' ' + d.toLocaleTimeString(); + return (<span>{date}</span>); + } else return (<span></span>); + } + })}, + {name: 'errorPort', title: 'Host:Port', component: React.createClass({ + render: function(){ + return ( <a href={this.props.model.get('errorWorkerLogLink')} target="_blank"> {this.props.model.get('errorHost')}:{this.props.model.get('errorPort')} </a>); + } + })}, + {name: 'error', title: 'Error'} + ]; + }, + render: function() { + if(this.state.componentObj.debug){ + $(".boot-switch.debug").bootstrapSwitch('state', true, true); + } else { + $(".boot-switch.debug").bootstrapSwitch('state', false, true); + } + if(this.systemFlag){ + $(".boot-switch.systemSum").bootstrapSwitch('state', true, true); + } else { + $(".boot-switch.systemSum").bootstrapSwitch('state', false, true); + } + var spoutFlag = (this.state.componentObj.componentType === 'spout' ? true: false); + return ( + <div> + <Breadcrumbs links={this.getLinks()} /> + <div className="row"> + <div className="col-sm-12"> + <div className="box filter"> + <div className="box-body form-horizontal"> + <div className="form-group no-margin"> + <label className="col-sm-1 control-label">Window</label> + <div className="col-sm-2"> + <select className="form-control" onChange={this.handleWindowChange} value={this.windowSize}> + {this.renderWindowOptions()} + </select> + </div> + <label className="col-sm-2 control-label">System Summary</label> + <div className="col-sm-2"> + <input className="boot-switch systemSum" type="checkbox" /> + </div> + <label className="col-sm-1 control-label">Debug</label> + <div className="col-sm-1"> + <input className="boot-switch debug" type="checkbox"/> + </div> + <div className="col-sm-3 text-right"> + <div className="btn-group" role="group"> + <button type="button" className="btn btn-primary" onClick={this.handleProfiling} title="Profiling & Debugging" data-rel="tooltip"> + <i className="fa fa-cogs"></i> + </button> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <div className="row"> + <div className="col-sm-4"> + <div className="summary-tile"> + <div className="summary-title">Component Summary</div> + <div className="summary-body"> + <p><strong>ID: </strong>{this.state.componentObj.id}</p> + <p><strong>Topology: </strong>{this.state.componentObj.name}</p> + <p><strong>Executors: </strong>{this.state.componentObj.executors}</p> + <p><strong>Tasks: </strong>{this.state.componentObj.tasks}</p> + <p><strong>Debug: </strong><a href={this.state.componentObj.eventLogLink} target="_blank">events</a></p> + </div> + </div> + </div> + <div className="col-sm-8"> + <div className="stats-tile"> + <div className="stats-title">{spoutFlag ? "Spout Stats" : "Bolt Stats"}</div> + <div className="stats-body"> + <table className="table table-condensed no-margin"> + <thead> + <tr> + <th><span data-rel="tooltip" title="The past period of time for which the statistics apply.">Window</span></th> + <th><span data-rel="tooltip" title="The number of Tuples emitted.">Emitted</span></th> + <th><span data-rel="tooltip" title="The number of Tuples emitted that sent to one or more bolts.">Transferred</span></th> + {spoutFlag ? <th><span data-rel="tooltip" title='The average time a Tuple "tree" takes to be completely processed by the Topology. A value of 0 is expected if no acking is done.'>Complete Latency (ms)</span></th> : null} + {!spoutFlag ? <th><span data-rel="tooltip" title="The average time a Tuple spends in the execute method. The execute method may complete without sending an Ack for the tuple.">Execute Latency (ms)</span></th> : null} + {!spoutFlag ? <th><span data-rel="tooltip" title="The number of incoming Tuples processed.">Executed</span></th> : null} + {!spoutFlag ? <th><span data-rel="tooltip" title="The average time it takes to Ack a Tuple after it is first received. Bolts that join, aggregate or batch may not Ack a tuple until a number of other Tuples have been received.">Process Latency (ms)</span></th> : null} + <th><span data-rel="tooltip" title={spoutFlag ? 'The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.' : "The number of Tuples acknowledged by this Bolt."}>Acked</span></th> + <th><span data-rel="tooltip" title={spoutFlag ? 'The number of Tuple "trees" that were explicitly failed or timed out before acking was completed. A value of 0 is expected if no acking is done.' : "The number of tuples Failed by this Bolt."}>Failed</span></th> + </tr> + </thead> + <tbody> + {this.renderStatsRow()} + </tbody> + </table> + </div> + </div> + </div> + </div> + <div className="row"> + <div className="col-sm-12"> + {this.state.componentObj.inputStats ? this.renderInputStats() : null} + {this.state.componentObj.outputStats ? this.renderOutputStats() : null} + {this.state.componentObj.executorStats ? this.renderExecutorStats() : null} + {this.state.componentObj.componentErrors ? this.renderErrorStats() : null} + </div> + </div> + {this.state.profilingModalOpen ? <ProfilingView modalId="modal-profiling" topologyId={this.props.id} executorStats={this.state.componentObj.executorStats} /> : null} + </div> + ); + }, + handleProfiling: function(){ + this.setState({"profilingModalOpen":true}); + }, + debugAction: function(toEnableFlag){ + if(toEnableFlag){ + bootbox.prompt({ + title: 'Do you really want to debug this component ? If yes, please, specify sampling percentage.', + value: "10", + buttons: { + confirm: { + label: 'Yes', + className: "btn-success", + }, + cancel: { + label: 'No', + className: "btn-default", + } + }, + callback: function(result) { + if(result != null){ + this.model.debugComponent({ + id: this.state.componentObj.topologyId, + name: this.state.componentObj.id, + debugType: 'enable', + percent: result, + success: function(model, response){ + if(response.error){ + Utils.notifyError(response.error); + } else { + this.initializeData(); + Utils.notifySuccess("Debugging enabled successfully."); + } + }.bind(this), + error: function(model, response, options){ + Utils.notifyError("Error occured in enabling debugging."); + } + }); + } else { + $(".boot-switch.debug").bootstrapSwitch('toggleState', true) + } + }.bind(this) + }); + } else { + var title = "Do you really want to stop debugging this component ?"; + var successCb = function(){ + this.model.debugComponent({ + id: this.state.componentObj.topologyId, + name: this.state.componentObj.id, + debugType: 'disable', + percent: '0', + success: function(model, response){ + if(response.error){ + Utils.notifyError(response.error); + } else { + this.initializeData(); + Utils.notifySuccess("Debugging disabled successfully."); + } + }.bind(this), + error: function(model, response, options){ + Utils.notifyError("Error occured in disabling debugging."); + } + }); + }.bind(this); + var cancelCb = function(){ + $(".boot-switch.debug").bootstrapSwitch('toggleState', true) + }.bind(this); + Utils.ConfirmDialog(' ', title, successCb, cancelCb); + } + }, + }); +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/529ef7f7/contrib/views/storm/src/main/resources/scripts/views/Dashboard.jsx ---------------------------------------------------------------------- diff --git a/contrib/views/storm/src/main/resources/scripts/views/Dashboard.jsx b/contrib/views/storm/src/main/resources/scripts/views/Dashboard.jsx new file mode 100644 index 0000000..3f4f682 --- /dev/null +++ b/contrib/views/storm/src/main/resources/scripts/views/Dashboard.jsx @@ -0,0 +1,65 @@ +/** + 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([ + 'jsx!components/Table', + 'jsx!components/RadialChart', + 'react', + 'react-dom', + 'jsx!containers/ClusterSummary', + 'jsx!containers/NimbusSummary', + 'jsx!containers/SupervisorSummary', + 'jsx!containers/TopologyListing', + 'jsx!containers/NimbusConfigSummary' + ],function(Table,RadialChart, React, ReactDOM, ClusterSummary, NimbusSummary, SupervisorSummary, TopologyListing, NimbusConfigSummary){ + 'use strict'; + + return React.createClass({ + displayName: 'Dashboard', + getInitialState: function(){ + return null; + }, + componentWillMount: function(){ + $('.loader').show(); + }, + componentDidMount: function(){ + $('.loader').hide(); + }, + componentWillUpdate: function(){ + $('.loader').show(); + }, + componentDidUpdate: function(){ + $('.loader').hide(); + }, + render: function() { + return ( + <div> + <div className="row" style={{marginTop: '20px'}}> + <ClusterSummary /> + <TopologyListing fromDashboard={true} /> + </div> + <div className="row"> + <div className="col-sm-12"> + <NimbusConfigSummary /> + </div> + </div> + </div> + ); + } + }); +}); \ No newline at end of file