http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/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..5847ef9
--- /dev/null
+++ 
b/contrib/views/storm/src/main/resources/scripts/views/ComponentDetailView.jsx
@@ -0,0 +1,534 @@
+/**
+ 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!components/SearchLogs',
+       'jsx!views/ProfilingView',
+       'utils/Utils',
+       'bootbox',
+       'bootstrap',
+       'bootstrap-switch'
+       ],function(Table, Pagination, React, ReactDOM, BaseCollection, 
VTopology, Breadcrumbs, SearchLogs, ProfilingView, Utils, bootbox){
+       'use strict';
+
+       return React.createClass({
+               displayName: 'ComponentDetailView',
+               propTypes: {
+                       id: React.PropTypes.string.isRequired,
+                       name: React.PropTypes.string.isRequired
+               },
+               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 || model.error){
+                                               
Utils.notifyError(response.error || 
model.error+'('+model.errorMessage.split('(')[0]+')');
+                                       } 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({
+                                               propTypes: {
+                                                       model: 
React.PropTypes.object.isRequired
+                                               },
+                                               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({
+                                               propTypes: {
+                                                       model: 
React.PropTypes.object.isRequired
+                                               },
+                                               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({
+                                               propTypes: {
+                                                       model: 
React.PropTypes.object.isRequired
+                                           },
+                                               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({
+                                               propTypes: {
+                                                       model: 
React.PropTypes.object.isRequired
+                                               },
+                                               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({
+                                       propTypes: {
+                                               model: 
React.PropTypes.object.isRequired
+                                       },
+                                       render: function(){
+                                               
if(this.props.model.get('errorTime') && this.props.model.get('errorTime') != 0) 
{
+                                                       var d = new 
Date(this.props.model.get('errorTime') * 1000),
+                                                       date = 
d.toLocaleDateString() + ' ' + d.toLocaleTimeString();
+                                                       return 
(<span>{date}</span>);
+                                               } else return (<span></span>);
+                                       }
+                               })},
+                               {name: 'errorPort', title: 'Host:Port', 
component: React.createClass({
+                                       propTypes: {
+                                               model: 
React.PropTypes.object.isRequired
+                                       },
+                                       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()} />
+                                       <SearchLogs 
id={this.state.componentObj.topologyId}/>
+                                       <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: this.state.componentObj.samplingPct ? 
this.state.componentObj.samplingPct : "10",
+                               buttons: {
+                                 confirm: {
+                                   label: 'Yes',
+                                   className: "btn-success",
+                                 },
+                                 cancel: {
+                                   label: 'No',
+                                   className: "btn-default",
+                                 }
+                               },
+                               callback: function(result) {
+                                         if(result == null) {
+                                               
$(".boot-switch.debug").bootstrapSwitch('toggleState', true);
+                                 } else if(result == "" || isNaN(result) || 
result < 0) {
+                                               Utils.notifyError("Enter valid 
sampling percentage");
+                                               
$(".boot-switch.debug").bootstrapSwitch('toggleState', true)
+                                 } else {
+                                   this.model.debugComponent({
+                                               id: 
this.state.componentObj.topologyId,
+                                               name: 
this.state.componentObj.id,
+                                               debugType: 'enable',
+                                               percent: result,
+                                               success: function(model, 
response){
+                                                       if(response.error || 
model.error){
+                                                                       
Utils.notifyError(response.error || 
model.error+'('+model.errorMessage.split('(')[0]+')');
+                                                               } else {
+                                                                       
this.initializeData();
+                                                               
Utils.notifySuccess("Debugging enabled successfully.");
+                                                               }
+                                               }.bind(this),
+                                                       error: function(model, 
response, options){
+                                                               
Utils.notifyError("Error occured in enabling debugging.");
+                                                       }
+                                       });
+                                 }
+                               }.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 || 
model.error){
+                                                               
Utils.notifyError(response.error || 
model.error+'('+model.errorMessage.split('(')[0]+')');
+                                                       } 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('&nbsp;', title, successCb, 
cancelCb);
+               }
+           },
+       });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/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

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/contrib/views/storm/src/main/resources/scripts/views/Footer.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/scripts/views/Footer.jsx 
b/contrib/views/storm/src/main/resources/scripts/views/Footer.jsx
new file mode 100644
index 0000000..98e63e9
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/Footer.jsx
@@ -0,0 +1,48 @@
+/**
+ 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', 'react-dom', 'models/VCluster', 'utils/Utils'], 
function(React, ReactDOM, VCluster, Utils) {
+       'use strict';
+       return React.createClass({
+               displayName: 'Footer',
+               getInitialState: function(){
+                       this.initializeData();
+                       return {
+                               version: 0
+                       };
+               },
+               initializeData: function(){
+                       this.model = new VCluster();
+                       this.model.fetch({
+                               success: function(model, response){
+                                       if(response.error || model.error){
+                                               
Utils.notifyError(response.error || 
model.error+'('+model.errorMessage.split('(')[0]+')');
+                                       } else {
+                                               this.setState({version: 
model.get('stormVersion')});
+                                       }
+                               }.bind(this),
+                               error: function(model, response, options){
+                                       Utils.notifyError("Error occured in 
fetching cluster summary data.");
+                               }
+                       });
+               },
+               render: function() {
+                       return (<p className="text-center">Apache Storm - 
v{this.state.version}</p>);
+               }
+       });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/contrib/views/storm/src/main/resources/scripts/views/NimbusSummaryView.jsx
----------------------------------------------------------------------
diff --git 
a/contrib/views/storm/src/main/resources/scripts/views/NimbusSummaryView.jsx 
b/contrib/views/storm/src/main/resources/scripts/views/NimbusSummaryView.jsx
new file mode 100644
index 0000000..6221d3f
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/NimbusSummaryView.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',
+       'react',
+       'react-dom',
+       'jsx!containers/NimbusSummary',
+       'jsx!components/Breadcrumbs'
+       ],function(Table, React, ReactDOM, NimbusSummary, Breadcrumbs){
+       'use strict';
+
+       return React.createClass({
+               displayName: 'NimbusSummaryView',
+               getInitialState: function(){
+                       return null;
+               },
+               componentWillMount: function(){
+                       $('.loader').show();
+               },
+               componentDidMount: function(){
+                       $('.loader').hide();
+               },
+               componentWillUpdate: function(){
+                       $('.loader').show();
+               },
+               componentDidUpdate: function(){
+                       $('.loader').hide();
+               },
+               render: function() {
+                       return (
+                               <div>                                   
+                                       <Breadcrumbs links={this.getLinks()} />
+                                       <div className="row">
+                                               <div className="col-sm-12">
+                                                       <NimbusSummary/>
+                                               </div>
+                                       </div>
+                               </div>
+                       );
+           },
+           getLinks: function() {
+               var links = [
+                               {link: '#!/dashboard', title: 'Dashboard'},
+                               {link: 'javascript:void(0);', title: 'Nimbus 
Summary'}
+                               ];
+                       return links;
+           }
+       });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/contrib/views/storm/src/main/resources/scripts/views/ProfilingView.jsx
----------------------------------------------------------------------
diff --git 
a/contrib/views/storm/src/main/resources/scripts/views/ProfilingView.jsx 
b/contrib/views/storm/src/main/resources/scripts/views/ProfilingView.jsx
new file mode 100644
index 0000000..f5ffefe
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/ProfilingView.jsx
@@ -0,0 +1,214 @@
+/**
+ 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', 
+       'react-dom',
+       'collections/BaseCollection',
+       'models/VTopology',
+       'utils/Utils', 
+       'utils/Globals', 
+       'jsx!components/Table',
+       'bootstrap'
+       ], function(React, ReactDOM, BaseCollection, VTopology, Utils, Globals, 
Table) {
+       'use strict';
+       return React.createClass({
+               displayName: 'Profiling',
+               propTypes: {
+                       modalId: React.PropTypes.string.isRequired,
+                       topologyId: React.PropTypes.string.isRequired,
+                       executorStats: React.PropTypes.array.isRequired
+               },
+               getInitialState: function(){
+                       this.model = new VTopology();
+                       this.selectedWorker = [];
+                       return null;
+               },
+               componentWillMount: function(){
+                       this.syncData();
+               },
+               componentDidMount: function(){
+                       $('.error-msg').hide();
+                       $('.warning-msg').hide();
+                       $('.success-msg').hide();
+               },
+               componentDidUpdate: function(){
+
+               },
+               syncData: function(){
+                       this.collection = new BaseCollection();
+                       if(this.props.executorStats.length){
+                               var data = {};
+                               this.props.executorStats.map(function(obj){
+                                       var hostPort = obj.host + ":" + 
obj.port;
+                                       if(!data[hostPort]){
+                                               data[hostPort] = {};
+                                       }
+                                       if(!data[hostPort].idArr){
+                                               data[hostPort].idArr = [];
+                                       }
+                                       data[hostPort].idArr.push(obj.id);
+                               });
+                               var keys = this.hostPortArr = _.keys(data);
+                               keys.map(function(key){
+                                       this.collection.add(new Backbone.Model({
+                                               hostPort: key,
+                                               executorId: data[key].idArr
+                                       }));
+                               }.bind(this));
+                       }
+               },
+               handleJStackOp: function(){
+                       this.performOp('JStack');
+               },
+               handleRestartWorker: function(){
+                       this.performOp('RestartWorker');
+               },
+               handleHeapOp: function(){
+                       this.performOp('Heap');
+               },
+               performOp: function(opType){
+                       if(!this.selectedWorker.length){
+                               $('.warning-msg').show();
+                               $('.success-msg').hide();
+                               $('.error-msg').hide();
+                       } else {
+                               $('.warning-msg').hide();
+                               $('.success-msg').hide();
+                               $('.error-msg').hide();
+                               var promiseArr = [];
+                               this.selectedWorker.map(function(worker){
+                                       var obj = {
+                                               id: this.props.topologyId,
+                                               hostPort: worker
+                                       };
+                                       if(opType === 'JStack'){
+                                               
promiseArr.push(this.model.profileJStack(obj));
+                                       } else if(opType === 'RestartWorker'){
+                                               
promiseArr.push(this.model.profileRestartWorker(obj));
+                                       } else if(opType === 'Heap'){
+                                               
promiseArr.push(this.model.profileHeap(obj));
+                                       }
+                               }.bind(this));
+                               Promise.all(promiseArr)
+                               .then(function(resultsArr){
+                                       $('.success-msg').show();
+                               })
+                               .catch(function(){
+                                       $('.error-msg').show();
+                               });
+                       }
+               },
+               getColumns: function(){
+                       var self = this;
+                       return [
+                               {
+                                       name: 'hostPort',
+                                       title: React.createClass({
+                                               handleChange: function(e){
+                                                       
if($(e.currentTarget).prop('checked')){
+                                                               
self.selectedWorker = self.hostPortArr;
+                                                               
$('[name="single"]').prop("checked", true)
+                                                       } else {
+                                                               
self.selectedWorker = [];
+                                                               
$('[name="single"]').prop("checked", false)
+                                                       }
+                                               },
+                                               render: function(){
+                                                       return (
+                                                               <input 
type="checkbox" name="selectAll" onChange={this.handleChange}/>
+                                                       );
+                                               }
+                                       }), 
+                                       component: React.createClass({
+                                               propTypes: {
+                                                       model: 
React.PropTypes.object.isRequired
+                                               },
+                                               handleChange: function(e){
+                                                       var hostPort = 
this.props.model.get('hostPort')
+                                                       
if($(e.currentTarget).prop('checked')){
+                                                               
self.selectedWorker.push(hostPort);
+                                                       } else {
+                                                               var index = 
_.indexOf(self.selectedWorker, hostPort);
+                                                               if(index > -1){
+                                                                       
self.selectedWorker.splice(index, 1);
+                                                               }
+                                                       }
+                                               },
+                                               render: function(){
+                                                       return (
+                                                               <input 
type="checkbox" name="single" onChange={this.handleChange}/>
+                                                       );
+                                               }
+                                       })
+                               },
+                               {name: 'hostPort', title:'Host:Port'},
+                               {name: 'executorId', title:'Executor Id', 
component: React.createClass({
+                                       propTypes: {
+                                               model: 
React.PropTypes.object.isRequired
+                                       },
+                                       render: function(){
+                                               var executors = 
this.props.model.get('executorId').join(', ');
+                                               return (
+                                                       <span>{executors}</span>
+                                               );
+                                       }
+                               })}
+                       ];
+               },
+               closeModal: function(){
+                       $('#'+this.props.modalId).modal("hide");
+               },
+               render: function() {
+                       return (
+                               <div className="modal fade" 
id={this.props.modalId} role="dialog">
+                                   <div className="modal-dialog">
+                                       <div className="modal-content">
+                                               <div className="modal-header">
+                                                       <button type="button" 
className="close" data-dismiss="modal">&times;</button>
+                                                       <h4 
className="modal-title">Profiling & Debugging</h4>
+                                               </div>
+                                               <div className="modal-body">
+                                                       <div className="alert 
alert-warning alert-dismissible warning-msg" role="alert">
+                                                                 
<strong>Warning!</strong> Please select atleast one worker to perform operation.
+                                                               </div>
+                                                               <div 
className="alert alert-success alert-dismissible success-msg" role="alert">
+                                                                 
<strong>Success!</strong> Action performed successfully.
+                                                               </div>
+                                                               <div 
className="alert alert-danger alert-dismissible error-msg" role="alert">
+                                                                 
<strong>Error!</strong> Error occured while performing the action.
+                                                               </div>
+                                                       <div 
className="clearfix">
+                                                                       <div 
className="btn-group btn-group-sm pull-right">
+                                                                               
<button type="button" className="btn btn-primary" 
onClick={this.handleJStackOp}>JStack</button>
+                                                                               
<button type="button" className="btn btn-primary" 
onClick={this.handleRestartWorker}>Restart Worker</button>
+                                                                               
<button type="button" className="btn btn-primary" 
onClick={this.handleHeapOp}>Heap</button>
+                                                                       </div>
+                                                               </div>
+                                                               <hr />
+                                                       <Table className="table 
table-bordered" collection={this.collection} columns={this.getColumns()} 
emptyText="No workers found !" />
+                                               </div>
+                                               <div className="modal-footer">
+                                                       <button type="button" 
className="btn btn-default" onClick={this.closeModal}>Close</button>
+                                               </div>
+                                       </div>
+                                   </div>
+                               </div>
+                       );
+               },
+       });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/contrib/views/storm/src/main/resources/scripts/views/RebalanceView.jsx
----------------------------------------------------------------------
diff --git 
a/contrib/views/storm/src/main/resources/scripts/views/RebalanceView.jsx 
b/contrib/views/storm/src/main/resources/scripts/views/RebalanceView.jsx
new file mode 100644
index 0000000..33f5963
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/RebalanceView.jsx
@@ -0,0 +1,223 @@
+/**
+ 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', 
+       'react-dom',
+       'utils/Utils', 
+       'models/VCluster', 
+       'utils/Globals', 
+       'bootstrap', 
+       'bootstrap-slider'], function(React, ReactDOM, Utils, VCluster, 
Globals) {
+       'use strict';
+       return React.createClass({
+               displayName: 'Rebalance',
+               propTypes: {
+                       modalId: React.PropTypes.string.isRequired,
+                       topologyId: React.PropTypes.string.isRequired,
+                       topologyExecutors: React.PropTypes.string.isRequired,
+                       spouts: React.PropTypes.array.isRequired,
+                       bolts: React.PropTypes.array.isRequired
+               },
+               getInitialState: function(){
+                       var spoutArr = [];
+                       var boltArr = [];
+                       this.getClusterDetails();
+                       return {
+                               spout: spoutArr,
+                               bolt: boltArr,
+                               workers: 
parseInt(this.props.topologyExecutors,10),
+                               waitTime: 30,
+                               freeSlots: 0
+                       };
+               },
+               componentWillMount: function(){
+                       this.syncData();
+               },
+               componentDidMount: function(){
+                       $('.error-msg').hide();
+               },
+               componentDidUpdate: function(){
+                       $('#ex1').slider({
+                               value: this.state.workers,
+                               min: 0,
+                               step: 1,
+                               max: this.state.workers + this.state.freeSlots,
+                               tooltip_position: 'bottom',
+                               formatter: function(value) {
+                                       return 'Current value: ' + value;
+                               }
+                       });
+               },
+               syncData: function(){
+                       var spoutArr, boltArr;
+                       if(this.props.spouts){
+                               spoutArr = 
this.props.spouts.map(function(spout){
+                                       var obj = {
+                                               key: spout.spoutId,
+                                               value: spout.executors
+                                       };
+                                       return obj;
+                               });
+                               this.setState({'spout': spoutArr});
+                       }
+                       if(this.props.bolts){
+                               boltArr = this.props.bolts.map(function(bolt){
+                                       var obj = {
+                                               key: bolt.boltId,
+                                               value: bolt.executors
+                                       };
+                                       return obj;
+                               });
+                               this.setState({'bolt': boltArr});
+                       }
+               },
+               getClusterDetails: function(){
+                       var model = new VCluster();
+                       model.fetch({
+                               success: function(model){
+                                       this.setState({"freeSlots": 
model.get('slotsFree')});
+                               }.bind(this)
+                       });
+               },
+               rebalanceTopologyAction: function(e){
+                       var arr = $('form').serializeArray();
+                       var errorFlag = false;
+                       var finalData = {
+                               "rebalanceOptions": {
+                                       "executors": {}
+                               },
+                       };
+                       var waitTime;
+                       var result = arr.map(function(obj){
+                               if(!errorFlag){
+                                       if(obj.value === ''){
+                                               errorFlag = true;
+                                       } else {
+                                               if(obj.name === 'workers'){
+                                                       
finalData.rebalanceOptions.numWorkers = obj.value;
+                                               } else if(obj.name === 
'waitTime'){
+                                                       waitTime = obj.value;
+                                               } else {
+                                                       
finalData.rebalanceOptions.executors[obj.name] = obj.value;
+                                               }
+                                       }
+                               }
+                       });
+                       if(errorFlag){
+                               $('.error-msg').show();
+                       } else {
+                               $('.error-msg').hide();
+                               $.ajax({
+                               url: Globals.baseURL + '/api/v1/topology/' + 
this.props.topologyId + '/rebalance/' + waitTime,
+                               data: 
(_.keys(finalData.rebalanceOptions).length) ? JSON.stringify(finalData) : null,
+                               cache: false,
+                               contentType: 'application/json',
+                               type: 'POST',
+                               success: function(model, response, options){
+                                 if(!_.isUndefined(model.error)){
+                                   if(model.errorMessage.search("msg:") != -1){
+                                     var startIndex = 
model.errorMessage.search("msg:") + 4;
+                                     var endIndex = 
model.errorMessage.split("\n")[0].search("\\)");
+                                     
Utils.notifyError(model.error+":<br/>"+model.errorMessage.substring(startIndex, 
endIndex));
+                                   } else {
+                                     Utils.notifyError(model.error);
+                                   }
+                                 } else {
+                                   Utils.notifySuccess("Topology rebalanced 
successfully.");
+                                 }
+                                 this.closeModal();
+                               }.bind(this),
+                               error: function(model, response, options){
+                                       Utils.notifyError("Error occured in 
rebalancing topology.");
+                               }
+                             });
+                       }
+               },
+               renderSpoutInput: function(){
+                       if(this.state.spout){
+                               return this.state.spout.map(function(spout, i){
+                                       return (
+                                               <div key={i} 
className="form-group">
+                                             <label className="control-label 
col-sm-3">{spout.key}*:</label>
+                                             <div className="col-sm-9">
+                                               <input type="number" min="0" 
name={spout.key} className="form-control" defaultValue={spout.value} 
required="required"/>
+                                             </div>
+                                           </div>
+                                       );
+                               });
+                       }
+               },
+               renderBoltInput: function(){
+                       if(this.state.bolt){
+                               return this.state.bolt.map(function(bolt, i){
+                                       return (
+                                               <div key={i} 
className="form-group">
+                                             <label className="control-label 
col-sm-3">{bolt.key}*:</label>
+                                             <div className="col-sm-9">
+                                               <input type="number" min="0" 
name={bolt.key} className="form-control" defaultValue={bolt.value} />
+                                             </div>
+                                           </div>
+                                       );
+                               });
+                       }
+               },
+               closeModal: function(){
+                       $('#'+this.props.modalId).modal("hide");
+               },
+               render: function() {
+                       var totalExecutor = this.state.workers + 
this.state.freeSlots;
+                       return (
+                               <div className="modal fade" 
id={this.props.modalId} role="dialog" data-backdrop="static">
+                                   <div className="modal-dialog">
+                                       <div className="modal-content">
+                                               <div className="modal-header">
+                                                       <button type="button" 
className="close" data-dismiss="modal">&times;</button>
+                                                       <h4 
className="modal-title">Rebalance Topology</h4>
+                                               </div>
+                                               <div className="modal-body">
+                                                       <div className="alert 
alert-danger alert-dismissible error-msg" role="alert">
+                                                                 
<strong>Warning!</strong> Please fill out all the required (*) fields.
+                                                               </div>
+                                                       <form 
className="form-horizontal" role="form">
+                                                                   <div 
className="form-group">
+                                                                     <label 
className="control-label col-sm-3">Workers*:</label>
+                                                                     <div 
className="col-sm-9">
+                                                                       
<b>0</b><input id="ex1" name="workers" data-slider-id='ex1Slider' type="text" 
/><b>{totalExecutor}</b>
+                                                                     </div>
+                                                                   </div>
+                                                                   
{this.renderSpoutInput()}
+                                                                   
{this.renderBoltInput()}
+                                                                   <div 
className="form-group">
+                                                                     <label 
className="control-label col-sm-3">Wait Time*:</label>
+                                                                     <div 
className="col-sm-9">
+                                                                       <input 
type="number" min="0" name="waitTime" className="form-control" 
defaultValue={this.state.waitTime}/>
+                                                                     </div>
+                                                                   </div>
+                                                                 </form>
+                                               </div>
+                                               <div className="modal-footer">
+                                                       <button type="button" 
className="btn btn-default" onClick={this.closeModal}>Close</button>
+                                                               <button 
type="button" className="btn btn-success" 
onClick={this.rebalanceTopologyAction}>Save</button>
+                                               </div>
+                                       </div>
+                                   </div>
+                               </div>
+                       );
+               },
+       });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cf5c068c/contrib/views/storm/src/main/resources/scripts/views/SupervisorSummaryView.jsx
----------------------------------------------------------------------
diff --git 
a/contrib/views/storm/src/main/resources/scripts/views/SupervisorSummaryView.jsx
 
b/contrib/views/storm/src/main/resources/scripts/views/SupervisorSummaryView.jsx
new file mode 100644
index 0000000..5827147
--- /dev/null
+++ 
b/contrib/views/storm/src/main/resources/scripts/views/SupervisorSummaryView.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',
+       'react',
+       'react-dom',
+       'jsx!containers/SupervisorSummary',
+       'jsx!components/Breadcrumbs'
+       ],function(Table, React, ReactDOM, SupervisorSummary, Breadcrumbs){
+       'use strict';
+
+       return React.createClass({
+               displayName: 'SupervisorSummaryView',
+               getInitialState: function(){
+                       return null;
+               },
+               componentWillMount: function(){
+                       $('.loader').show();
+               },
+               componentDidMount: function(){
+                       $('.loader').hide();
+               },
+               componentWillUpdate: function(){
+                       $('.loader').show();
+               },
+               componentDidUpdate: function(){
+                       $('.loader').hide();
+               },
+               render: function() {                    
+                       return (
+                               <div>                                   
+                                       <Breadcrumbs links={this.getLinks()} />
+                                       <div className="row">
+                                               <div className="col-sm-12">
+                                                       <SupervisorSummary/>
+                                               </div>
+                                       </div>
+                               </div>
+                       );
+           },
+           getLinks: function() {
+               var links = [
+                               {link: '#!/dashboard', title: 'Dashboard'},
+                               {link: 'javascript:void(0);', title: 
'Supervisor Summary'}
+                               ];
+                       return links;
+           }
+       });
+});
\ No newline at end of file

Reply via email to