You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2017/10/20 21:01:02 UTC
[05/22] ambari git commit: Revert "AMBARI-21955. Update React version
to 15.6.2 to get MIT license. (Sanket Shah via yusaku)"
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/scripts/views/TopologyDetailView.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/scripts/views/TopologyDetailView.jsx b/contrib/views/storm/src/main/resources/scripts/views/TopologyDetailView.jsx
new file mode 100644
index 0000000..136d95f
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/TopologyDetailView.jsx
@@ -0,0 +1,1039 @@
+/**
+ 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',
+ 'utils/Utils',
+ 'react',
+ 'react-dom',
+ 'collections/BaseCollection',
+ 'models/VTopology',
+ 'models/BaseModel',
+ 'jsx!containers/TopologyConfiguration',
+ 'jsx!containers/TopologyDetailGraph',
+ 'jsx!components/Breadcrumbs',
+ 'jsx!components/SearchLogs',
+ 'jsx!components/BarChart',
+ 'jsx!views/RebalanceView',
+ 'bootbox',
+ 'x-editable',
+ 'bootstrap',
+ 'bootstrap-switch'
+ ],function(Table, Pagination, Utils, React, ReactDOM, BaseCollection, VTopology, BaseModel, TopologyConfiguration, TopologyDetailGraph, Breadcrumbs, SearchLogs, BarChart, RebalanceView, bootbox, XEditable){
+ 'use strict';
+
+ return React.createClass({
+ displayName: 'TopologyDetailView',
+ propTypes: {
+ id: React.PropTypes.string.isRequired
+ },
+ getInitialState: function(){
+ this.model = new VTopology({'id': this.props.id});
+ this.spoutCollection = new BaseCollection();
+ this.boltCollection = new BaseCollection();
+ this.lagCollection = new BaseCollection();
+ this.systemFlag = false;
+ this.windowSize = ':all-time';
+ return {
+ model: this.model,
+ graphData: {},
+ logLevels: {},
+ rebalanceModalOpen: false,
+ lagData: [],
+ hideKafkaLagBox: false,
+ workerHostPort: ''
+ };
+ },
+ componentWillMount: function(){
+ $('.loader').show();
+ this.initializeData();
+ },
+ componentDidMount: function(){
+ $(".boot-switch.systemSum").bootstrapSwitch({
+ size: 'small',
+ onSwitchChange: function(event, state){
+ this.systemFlag = state;
+ this.initializeData();
+ }.bind(this)
+ });
+ $("#slideContent").hide();
+ $(".boot-switch.debug").bootstrapSwitch({
+ size: 'small',
+ onSwitchChange: function(event, state){
+ this.debugAction(state);
+ }.bind(this)
+ });
+ $("#lag-graph").hide();
+ $("#kafkaSpout").bootstrapSwitch({
+ onSwitchChange: function() {
+ $('#lag-graph, #lag-table').slideToggle();
+ }
+ });
+ $('[data-rel="tooltip"]').tooltip();
+ $('.loader').hide();
+ },
+ componentWillUpdate: function(){
+ $('#collapse-spout').off('hidden.bs.collapse');
+ $('#collapse-spout').off('shown.bs.collapse');
+ $('#collapse-bolt').off('hidden.bs.collapse');
+ $('#collapse-bolt').off('shown.bs.collapse');
+ $('#modal-rebalance').off('hidden.bs.modal');
+ this.spoutCollection.getFirstPage().fullCollection.reset([]);
+ this.spouts = this.renderSpouts();
+ this.boltCollection.getFirstPage().fullCollection.reset([]);
+ this.bolts = this.renderBolts();
+ },
+ componentDidUpdate: function(){
+ $('#collapse-spout').on('hidden.bs.collapse', function () {
+ $("#spout-box").toggleClass("fa-compress fa-expand");
+ }).on('shown.bs.collapse', function() {
+ $("#spout-box").toggleClass("fa-compress fa-expand");
+ });
+
+ $('#collapse-bolt').on('hidden.bs.collapse', function () {
+ $("#bolt-box").toggleClass("fa-compress fa-expand");
+ }).on('shown.bs.collapse', function() {
+ $("#bolt-box").toggleClass("fa-compress fa-expand");
+ });
+ $('#modal-rebalance').on('hidden.bs.modal', function (e) {
+ this.initializeData();
+ this.setState({"rebalanceModalOpen":false});
+ }.bind(this));
+ if(this.state.rebalanceModalOpen){
+ $('#modal-rebalance').modal("show");
+ }
+ if(this.refs.barChart){
+ ReactDOM.findDOMNode(document.getElementById('lag-graph')).appendChild(this.refs.barChart.legendsEl)
+ }
+ },
+ initializeData: function(){
+ this.model.getData({
+ id: this.model.get('id'),
+ 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.model.set(model);
+ this.setState({"model": this.model});
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in fetching topology details.");
+ }
+ });
+ this.initializeGraphData();
+ this.initializeLogConfig();
+ this.initializeLagData();
+ this.initializeWorkerData();
+ },
+ initializeGraphData: function(){
+ $('#graphLoader').show();
+ this.model.getGraphData({
+ id: this.model.get('id'),
+ window: this.windowSize,
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ if(_.isString(model)){
+ model = JSON.parse(model);
+ }
+ this.setState({graphData: model});
+ }
+ $('#graphLoader').hide();
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in fetching topology visualization data.");
+ }
+ });
+ },
+
+ initializeLogConfig: function() {
+ this.collection = new BaseCollection();
+ this.model.getLogConfig({
+ id: this.model.get('id'),
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.resetLogCollection(model);
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in fetching log configuration data.");
+ }
+ });
+ },
+
+ initializeLagData: function(){
+ $('#kafkaLoader').show();
+ this.model.getTopologyLag({
+ id: this.model.get('id'),
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ if(model && _.keys(model).length > 0){
+ var keys = _.keys(model);
+ var arr = [];
+ for(var i = 0; i < keys.length; i++){
+ var data = model[keys[i]];
+ var topicKeys = _.keys(data.spoutLagResult);
+ for(var j = 0; j < topicKeys.length; j++){
+ var topicName = topicKeys[j];
+ var partitionData = data.spoutLagResult[topicName];
+ var id = _.keys(partitionData);
+ for(var k = 0; k < id.length; k++){
+ var partitionId = id[k];
+ var obj = partitionData[partitionId];
+ obj['spoutId'] = data.spoutId;
+ obj['spoutType'] = data.spoutType;
+ obj['partition'] = partitionId;
+ obj['topic'] = topicName;
+ arr.push(obj);
+ }
+ }
+ }
+ this.resetLagCollection(arr);
+ } else {
+ this.setState({hideKafkaLagBox : true});
+ }
+ }
+ $('#kafkaLoader').hide();
+ }.bind(this)
+ })
+ },
+ initializeWorkerData: function(){
+ this.model.getWorkerHost({
+ id: this.model.get('id'),
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ var workerHostPortArr = model.hostPortList;
+ var result = '';
+ for(var i = 0; i < workerHostPortArr.length; i++){
+ result += workerHostPortArr[i].host+':'+workerHostPortArr[i].port
+ if(i !== workerHostPortArr.length - 1){
+ result += ', \n';
+ }
+ }
+ this.setState({'workerHostPort': result})
+ }
+ }.bind(this)
+ })
+ },
+ resetLagCollection: function(model){
+ this.lagCollection.reset(model);
+ this.setState({"lagData": model});
+ },
+ getLagColums: function(){
+ var self = this;
+ return [
+ {name: 'spoutId', title: 'Id', tooltip:'Id'},
+ {name: 'topic', title: 'Topic', tooltip:'Topic'},
+ {name: 'partition', title: 'Partition', tooltip:'Partition'},
+ {name: 'logHeadOffset', title: 'Latest Offset', tooltip:'Latest Offset'},
+ {name: 'consumerCommittedOffset', title: 'Spout Committed Offset', tooltip:'Spout Committed Offset'},
+ {name: 'lag', title: 'Lag', tooltip:'Lag'},
+ ];
+ },
+ resetLogCollection: function(model) {
+ this.collection.reset();
+ this.setState({logLevels: model.namedLoggerLevels});
+ var keys = _.keys(this.state.logLevels);
+ keys.map(function(key, index) {
+ var obj = this.state.logLevels[key];
+ var model = new BaseModel({
+ logger: key,
+ target_level: obj.target_level,
+ timeout: obj.timeout,
+ timeout_epoch: obj.timeout_epoch
+ });
+ this.collection.add(model);
+ }.bind(this));
+
+ this.collection.add(new BaseModel({
+ logger: 'com.your.organization.LoggerName',
+ target_level: 'ALL',
+ timeout: 30,
+ timeout_epoch: 0,
+ isAdd: true
+ }));
+ },
+
+ 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}</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()} />
+ <Pagination collection={collection} />
+ </div>
+ </div>
+ );
+ },
+ renderSpouts: function(){
+ if(this.state.model.has('spouts')){
+ Utils.ArrayToCollection(this.state.model.get('spouts'), this.spoutCollection);
+ this.spoutCollection.searchFields = ['spoutId'];
+ var searchCb = function(e){
+ var value = e.currentTarget.value;
+ this.spoutCollection.search(value);
+ }.bind(this);
+ var toggleCb = function(e){
+ $("#collapse-spout").collapse('toggle');
+ }
+ return this.renderAccordion('spout', 'Spouts', 'id', searchCb, this.spoutCollection, 'No spouts found !', this.getSpoutColumns, toggleCb);
+ } else {
+ return null;
+ }
+ },
+ getSpoutColumns: function(){
+ var self = this;
+ return [
+ {name: 'spoutId', title: 'Id', tooltip:'The ID assigned to a the Component by the Topology. Click on the name to view the Component\'s page.', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ var topologyId = self.state.model.has('id') ? self.state.model.get('id') : "";
+ return ( <a href={"#!/topology/"+topologyId+"/component/"+this.props.model.get('spoutId')}>{this.props.model.get('spoutId')}</a>);
+ }
+ })},
+ {name: 'executors', title: 'Executors', tooltip:'Executors are threads in a Worker process.'},
+ {name: 'tasks', title: 'Tasks', tooltip:'A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.'},
+ {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: 'errorHost', title: 'Error Host:Port', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ return (<span>{this.props.model.has('errorHost') && this.props.model.get('errorHost') !== '' ? this.props.model.get('errorHost')+':'+this.props.model.get('errorPort') : null}</span>);
+ }
+ })},
+ {name: 'lastError', title: 'Last Error'},
+ {name: 'errorTime', title: 'Error 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>);
+ }
+ })}
+ ];
+ },
+ renderBolts: function(){
+ if(this.state.model.has('bolts')){
+ Utils.ArrayToCollection(this.state.model.get('bolts'), this.boltCollection);
+ this.boltCollection.searchFields = ['boltId'];
+ var searchCb = function(e){
+ var value = e.currentTarget.value;
+ this.boltCollection.search(value);
+ }.bind(this);
+ var toggleCb = function(e){
+ $("#collapse-bolt").collapse('toggle');
+ }
+ return this.renderAccordion('bolt', 'Bolts', 'id', searchCb, this.boltCollection, 'No bolts found !', this.getBoltColumns, toggleCb);
+ } else {
+ return null;
+ }
+ },
+ getBoltColumns: function(){
+ var self = this;
+ return [
+ {name: 'boltId', title: 'Id', tooltip:'The ID assigned to a the Component by the Topology. Click on the name to view the Component\'s page.', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ var topologyId = self.state.model.has('id') ? self.state.model.get('id') : "";
+ return ( <a href={"#!/topology/"+topologyId+"/component/"+this.props.model.get('boltId')}>{this.props.model.get('boltId')}</a>);
+ }
+ })},
+ {name: 'executors', title: 'Executors', tooltip:'Executors are threads in a Worker process.'},
+ {name: 'tasks', title: 'Tasks', tooltip:'A Task is an instance of a Bolt or Spout. The number of Tasks is almost always equal to the number of Executors.'},
+ {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: 'errorHost', title: 'Error Host:Port', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ return (<span>{this.props.model.has('errorHost') && this.props.model.get('errorHost') !== '' ? this.props.model.get('errorHost')+':'+this.props.model.get('errorPort') : null}</span>);
+ }
+ })},
+ {name: 'lastError', title: 'Last Error'},
+ {name: 'errorTime', title: 'Error 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>);
+ }
+ })}
+ ];
+ },
+ renderWindowOptions: function(){
+ if(this.state.model.has('topologyStats')){
+ return this.state.model.get('topologyStats').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: 'javascript:void(0);', title: this.state.model.has('name') ? this.state.model.get('name') : ""}
+ ];
+ return links;
+ },
+
+ addLogLevel: function(e) {
+ var self = this;
+ var id = e.currentTarget.getAttribute('data-name');
+ var namedLoggerLevels = {};
+ var targetLevel = $(e.currentTarget).parent().siblings().find('.target-level').val(),
+ timeout = $(e.currentTarget).parent().siblings().find('.timeout').html(),
+ logger = $(e.currentTarget).parent().siblings().find('.logger').html();
+
+ namedLoggerLevels[logger] = {
+ target_level: targetLevel,
+ reset_level: 'INFO',
+ timeout: parseInt(timeout, 10)
+ };
+
+ var dataObj = {
+ namedLoggerLevels: namedLoggerLevels
+ }
+
+ this.model.saveLogConfig({
+ id: this.model.get('id'),
+ data: JSON.stringify(dataObj),
+ contentType: "application/json",
+ success: function(model, response, options){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.resetLogCollection(model);
+ Utils.notifySuccess("Log configuration added successfully.");
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in saving log configuration data.");
+ }
+
+ });
+ },
+ applyLogLevel: function(e) {
+ var self = this;
+ var id = e.currentTarget.getAttribute('data-name');
+ var namedLoggerLevels = {};
+ var targetLevel = $(e.currentTarget).parents('td').siblings().find('.target-level').val(),
+ timeout = $(e.currentTarget).parents('td').siblings().find('.timeout').html(),
+ logger = $(e.currentTarget).parents('td').siblings().find('.logger').html();
+
+ namedLoggerLevels[logger] = {
+ target_level: targetLevel,
+ reset_level: 'INFO',
+ timeout: parseInt(timeout, 10)
+ };
+
+ var dataObj = {
+ namedLoggerLevels: namedLoggerLevels
+ }
+
+ this.model.saveLogConfig({
+ id: this.model.get('id'),
+ data: JSON.stringify(dataObj),
+ contentType: "application/json",
+ success: function(model, response, options){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.resetLogCollection(model);
+ Utils.notifySuccess("Log configuration applied successfully.");
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in applying log configuration data.");
+ }
+ });
+ },
+ clearLogLevel: function(e) {
+ var self = this;
+ var id = e.currentTarget.getAttribute('data-name');
+ var namedLoggerLevels = {};
+ var logger = $(e.currentTarget).parents('td').siblings().find('.logger').html();
+
+ namedLoggerLevels[logger] = {
+ target_level: null,
+ reset_level: 'INFO',
+ timeout: 0
+ };
+
+ var dataObj = {
+ namedLoggerLevels: namedLoggerLevels
+ }
+
+ this.model.saveLogConfig({
+ id: this.model.get('id'),
+ data: JSON.stringify(dataObj),
+ contentType: "application/json",
+ success: function(model, response, options){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.resetLogCollection(model);
+ Utils.notifySuccess("Log configuration cleared successfully.");
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in clearing log configuration data.");
+ }
+ });
+ },
+ getColumns: function(){
+ var self = this;
+ return [
+ {name: 'logger', title: 'Logger', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ if(this.props.model.get('isAdd'))
+ return (<a href="javascript:void(0)" className="x-editable logger">{this.props.model.get('logger')}</a>);
+ else return (<a href="javascript:void(0)" className="logger">{this.props.model.get('logger')}</a>);
+ },
+ componentDidMount: function() {
+ $(".x-editable").editable({
+ mode: 'inline'
+ });
+ }})
+ },
+ {name: 'target_level', title: 'Level', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function() {
+ return (
+ <select className="form-control target-level" defaultValue={this.props.model.get('target_level')}>
+ <option value="ALL">ALL</option>
+ <option value="TRACE">TRACE</option>
+ <option value="DEBUG">DEBUG</option>
+ <option value="INFO">INFO</option>
+ <option value="WARN">WARN</option>
+ <option value="ERROR">ERROR</option>
+ <option value="FATAL">FATAL</option>
+ <option value="OFF">OFF</option>
+ </select>
+ );
+ }
+ })},
+ {name: 'timeout', title: 'Timeout', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ return (<a href="javascript:void(0)" className="x-editable timeout">{this.props.model.get('timeout')}</a>);
+ },
+ componentDidMount: function() {
+ $(".x-editable").editable({
+ mode: 'inline'
+ });
+ }})
+ },
+ {name: 'timeout_epoch', title: 'Expires At', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ if(this.props.model.get('timeout_epoch') != 0) {
+ var d = new Date(this.props.model.get('timeout_epoch')),
+ date = d.toLocaleDateString() + ' ' + d.toLocaleTimeString();
+ return (<span>{date}</span>);
+ } else return (<span></span>);
+
+ }
+ })
+ },
+ {name: 'action', title: 'Action', component: React.createClass({
+ propTypes: {
+ model: React.PropTypes.object.isRequired
+ },
+ render: function(){
+ if(this.props.model.get('isAdd'))
+ return(
+ <a href="javascript:void(0)" data-name={this.props.model.get('logger')} className="btn btn-primary btn-xs" onClick={self.addLogLevel}><i className="fa fa-plus"></i></a>
+ )
+ else
+ return (
+ <span>
+ <a href="javascript:void(0)" data-name={this.props.model.get('logger')} className="btn btn-success btn-xs" onClick={self.applyLogLevel}><i className="fa fa-check"></i></a>
+ <a href="javascript:void(0)" data-name={this.props.model.get('logger')} className="btn btn-danger btn-xs" onClick={self.clearLogLevel}><i className="fa fa-times"></i></a>
+ </span>
+ );
+ }
+ })}
+ ];
+ },
+ toggleSlide: function() {
+ $("#slideContent").slideToggle();
+ },
+
+ renderStatsRow: function(){
+ var statsArr = this.state.model.get('topologyStats');
+ if(statsArr){
+ return statsArr.map(function(stats, i){
+ return (
+ <tr key={i}>
+ <td>{stats.windowPretty}</td>
+ <td>{stats.emitted}</td>
+ <td>{stats.transferred}</td>
+ <td>{stats.completeLatency}</td>
+ <td>{stats.acked}</td>
+ <td>{stats.failed}</td>
+ </tr>
+ );
+ });
+ }
+ },
+ render: function() {
+ var status = this.state.model.has('status') ? this.state.model.get('status') : null;
+ var workersTotal = this.state.model.has('workersTotal') ? this.state.model.get('workersTotal').toString() : '0';
+ if(this.state.model.get('debug')){
+ $(".boot-switch.debug").bootstrapSwitch('state', true, true);
+ } else {
+ $(".boot-switch.debug").bootstrapSwitch('state', false, true);
+ }
+ return (
+ <div>
+ <Breadcrumbs links={this.getLinks()} />
+ <SearchLogs id={this.model.get('id')}/>
+ <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.handleTopologyActivation} title="Activate" data-rel="tooltip" disabled={status === 'ACTIVE' ? "disabled" : null}>
+ <i className="fa fa-play"></i>
+ </button>
+ <button type="button" className="btn btn-primary" onClick={this.handleTopologyDeactivation} title="Deactivate" data-rel="tooltip" disabled={status === 'INACTIVE' ? "disabled" : null}>
+ <i className="fa fa-stop"></i>
+ </button>
+ <button type="button" className="btn btn-primary" onClick={this.handleTopologyRebalancing} title="Rebalance" data-rel="tooltip" disabled={status === 'REBALANCING' ? "disabled" : null}>
+ <i className="fa fa-balance-scale"></i>
+ </button>
+ <button type="button" className="btn btn-primary" onClick={this.handleTopologyKilling} title="Kill" data-rel="tooltip" disabled={status === 'KILLED' ? "disabled" : null}>
+ <i className="fa fa-ban"></i>
+ </button>
+ <button type="button" className="btn btn-primary" onClick={this.toggleSlide} title="Change Log Level" data-rel="tooltip">
+ <i className="fa fa-file-o"></i>
+ </button>
+ </div>
+ </div>
+ </div>
+ <div className="row" id="slideContent">
+ <div className="col-sm-12">
+ <hr/>
+ <h4 className="col-sm-offset-5">Change Log Level</h4>
+ <p>Modify the logger levels for topology. Note that applying a setting restarts the timer in the workers. To configure the root logger, use the name ROOT.</p>
+ <Table className="table no-margin" collection={this.collection} columns={this.getColumns()}/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div className="row">
+ <div className="col-sm-5">
+ <div className="summary-tile">
+ <div className="summary-title">Topology Summary</div>
+ <div className="summary-body form-horizontal">
+ <div className="form-group">
+ <label className="col-sm-4 control-label">ID:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('id')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Owner:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('owner')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Status:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('status')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Uptime:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('uptime')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Workers:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('workersTotal')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Executors:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('executorsTotal')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Tasks:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('tasksTotal')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Memory:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static">{this.state.model.get('assignedTotalMem')}</p>
+ </div>
+ </div>
+ <div className="form-group">
+ <label className="col-sm-4 control-label">Worker-Host:Port:</label>
+ <div className="col-sm-8">
+ <p className="form-control-static preformatted">{this.state.workerHostPort}</p>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ <div className="col-sm-7">
+ <div className="stats-tile">
+ <div className="stats-title">Topology Stats</div>
+ <div className="stats-body">
+ <table className="table table-enlarge">
+ <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>
+ <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>
+ <th><span data-rel="tooltip" title='The number of Tuple "trees" successfully processed. A value of 0 is expected if no acking is done.'>Acked</span></th>
+ <th><span data-rel="tooltip" title='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.'>Failed</span></th>
+ </tr>
+ </thead>
+ <tbody>
+ {this.renderStatsRow()}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div className="row">
+ <div className="col-sm-12">
+ <div className="inner-loader" id="graphLoader" />
+ <TopologyDetailGraph model={this.state.model} graphData={this.state.graphData}/>
+ </div>
+ </div>
+ {this.state.hideKafkaLagBox ? null :
+ <div className="row">
+ <div className="col-sm-12">
+ <div className="box">
+ <div className="box-header">
+ <h4>Kafka Spout Lag</h4>
+ <div className="box-control">
+ <input
+ id="kafkaSpout"
+ type="checkbox"
+ data-size="mini"
+ data-off-color="success"
+ data-off-text="Table"
+ data-on-color="info"
+ data-on-text="Graph" />
+ </div>
+ </div>
+ <div className="box-body">
+ <div className="row">
+ <div className="col-sm-12">
+ <div className="inner-loader" id="kafkaLoader" />
+ <div id="lag-graph">
+ {this.lagCollection.length > 0 ?
+ <BarChart
+ ref="barChart"
+ width={window != window.parent ? 1100 : 1300}
+ height={400}
+ xAttr="spoutId-partition"
+ yAttr="count"
+ data={this.lagCollection.toJSON().map(function(d){
+ return {
+ 'Latest Offset': d.logHeadOffset,
+ 'Spout Committed Offset': d.consumerCommittedOffset,
+ 'spoutId-partition': d.spoutId+'-'+d.partition
+ };
+ })}
+ />
+ : null}
+ </div>
+ <div id="lag-table">
+ <Table
+ className="table table-striped table-bordered"
+ collection={this.lagCollection}
+ emptyText="No Data Found."
+ columns={this.getLagColums()}
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ }
+ <div className="row">
+ <div className="col-sm-12">
+ {this.spouts}
+ </div>
+ </div>
+ <div className="row">
+ <div className="col-sm-12">
+ {this.bolts}
+ </div>
+ </div>
+ <div className="row">
+ <div className="col-sm-12">
+ <TopologyConfiguration configArr={this.state.model.get('configuration') ? this.state.model.get('configuration') : {}}/>
+ </div>
+ </div>
+ {this.state.rebalanceModalOpen ? <RebalanceView modalId="modal-rebalance" topologyId={this.state.model.get('id')} topologyExecutors={workersTotal} spouts={this.state.model.get('spouts') ? this.state.model.get('spouts') : []} bolts={this.state.model.get('bolts') ? this.state.model.get('bolts') : []}/> : null}
+ </div>
+ );
+ },
+ handleTopologyActivation: function(e){
+ if(this.model.get('status') !== 'ACTIVE'){
+ var msg = "Do you really want to activate this topology ?";
+ var successCb = function(){
+ this.model.activateTopology({
+ id: this.model.get('id'),
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.initializeData();
+ Utils.notifySuccess("Topology activated successfully.")
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in activating topology.");
+ }
+ });
+ }.bind(this);
+ Utils.ConfirmDialog(msg, '', successCb);
+ }
+ },
+ handleTopologyDeactivation: function(e){
+ if(this.model.get('status') !== 'INACTIVE'){
+ var msg = "Do you really want to deactivate this topology ?";
+ var successCb = function(){
+ this.model.deactivateTopology({
+ id: this.model.get('id'),
+ success: function(model, response){
+ if(response.error || model.error){
+ Utils.notifyError(response.error || model.error+'('+model.errorMessage.split('(')[0]+')');
+ } else {
+ this.initializeData();
+ Utils.notifySuccess("Topology deactivated successfully.")
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in deactivating topology.");
+ }
+ });
+ }.bind(this);
+ Utils.ConfirmDialog(msg, '', successCb);
+ }
+ },
+ handleTopologyRebalancing: function(e){
+ if(this.model.get('status') !== 'REBALANCING'){
+ this.setState({"rebalanceModalOpen":true});
+ }
+ },
+ handleTopologyKilling: function(e){
+ if(this.model.get('status') !== 'KILLED'){
+ bootbox.prompt({
+ title: 'Are you sure you want to kill this topology ? If yes, please, specify wait time in seconds.',
+ value: "30",
+ buttons: {
+ confirm: {
+ label: 'Yes',
+ className: "btn-success",
+ },
+ cancel: {
+ label: 'No',
+ className: "btn-default",
+ }
+ },
+ callback: function(result) {
+ if(result != null){
+ this.model.killTopology({
+ id: this.model.get('id'),
+ waitTime: 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("Topology killed successfully.")
+ }
+ }.bind(this),
+ error: function(model, response, options){
+ Utils.notifyError("Error occured in killing topology.");
+ }
+ });
+ }
+ }.bind(this)
+ });
+ }
+ },
+ debugAction: function(toEnableFlag){
+ if(toEnableFlag){
+ bootbox.prompt({
+ title: 'Do you really want to debug this topology ? If yes, please, specify sampling percentage.',
+ value: this.model.get("samplingPct") ? this.model.get("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.debugTopology({
+ id: this.model.get('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 topology ?";
+ var successCb = function(){
+ this.model.debugTopology({
+ id: this.model.get('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(' ', title, successCb, cancelCb);
+ }
+ },
+ });
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/scripts/views/TopologyListingView.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/scripts/views/TopologyListingView.jsx b/contrib/views/storm/src/main/resources/scripts/views/TopologyListingView.jsx
new file mode 100644
index 0000000..25441fa
--- /dev/null
+++ b/contrib/views/storm/src/main/resources/scripts/views/TopologyListingView.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/TopologyListing',
+ 'jsx!components/Breadcrumbs'
+ ],function(Table, React, ReactDOM, TopologyListing, Breadcrumbs){
+ 'use strict';
+
+ return React.createClass({
+ displayName: 'TopologyListingView',
+ 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">
+ <TopologyListing />
+ </div>
+ </div>
+ </div>
+ );
+ },
+ getLinks: function() {
+ var links = [
+ {link: '#!/dashboard', title: 'Dashboard'},
+ {link: 'javascript:void(0);', title: 'Topology Listing'}
+ ];
+ return links;
+ }
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/styles/style.css
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/styles/style.css b/contrib/views/storm/src/main/resources/styles/style.css
index 71c26c4..f6b1685 100644
--- a/contrib/views/storm/src/main/resources/styles/style.css
+++ b/contrib/views/storm/src/main/resources/styles/style.css
@@ -14,7 +14,7 @@
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.
-**/
+*/
/*
Theme: Apache Storm
Author: Sanket
@@ -37,12 +37,12 @@ body {
.row-margin-bottom {
margin-bottom: 20px;
}
-
-.table-borderless>tbody>tr>td,
-.table-borderless>tbody>tr>th,
-.table-borderless>tfoot>tr>td,
-.table-borderless>tfoot>tr>th,
-.table-borderless>thead>tr>td,
+
+.table-borderless>tbody>tr>td,
+.table-borderless>tbody>tr>th,
+.table-borderless>tfoot>tr>td,
+.table-borderless>tfoot>tr>th,
+.table-borderless>thead>tr>td,
.table-borderless>thead>tr>th {
border-top: none;
}
@@ -140,8 +140,7 @@ body {
}
/* Boxes */
-.box,
-.panel.panel-default {
+.box {
position: relative;
margin-bottom: 15px;
border: 1px #bcbcbc solid;
@@ -162,8 +161,8 @@ body {
border-bottom: 1px #bcbcbc solid;
border-radius: 4px 4px 0px 0px;
}
-.box .box-header h4 {
- float: left;
+.box .box-header h4 {
+ float: left;
margin: 0px;
font-size: 16px;
font-weight: 700;
@@ -171,12 +170,12 @@ body {
letter-spacing: 1px;
}
.box .box-header .box-control {
- float: right;
+ float: right;
}
.box .box-header .box-control .bootstrap-switch {
margin: 9px 2px;
}
-.box .box-header .box-control a,.box-control a {
+.box .box-header .box-control a {
display: inline-block;
width: 20px;
height: 20px;
@@ -188,21 +187,18 @@ body {
background-color: #4b4b4b;
color: rgba(255,255,255,0.75);
}
-.box-control a {
- margin: 0 2px;
-}
/*.box .box-header .box-control a i {
visibility: hidden;
}
.box .box-header .box-control:hover a i {
visibility: visible;
}*/
-.box .box-header .box-control a.primary, .box-control a.primary {background-color: #1b75bb;}
-.box .box-header .box-control a.success, .box-control a.success {background-color: #1bbb60;}
-.box .box-header .box-control a.info, .box-control a.info {background-color: #27a9e1;}
-.box .box-header .box-control a.warning, .box-control a.warning {background-color: #fbaf3f;}
-.box .box-header .box-control a.danger, .box-control a.danger {background-color: #ff5816;}
-.box .box-header .box-control a.secondary, .box-control a.secondary {background-color: #df206a;}
+.box .box-header .box-control a.primary {background-color: #1b75bb;}
+.box .box-header .box-control a.success {background-color: #1bbb60;}
+.box .box-header .box-control a.info {background-color: #27a9e1;}
+.box .box-header .box-control a.warning {background-color: #fbaf3f;}
+.box .box-header .box-control a.danger {background-color: #ff5816;}
+.box .box-header .box-control a.secondary {background-color: #df206a;}
.box .box-body {
padding: 10px;
@@ -289,7 +285,7 @@ body {
.tile.warning > .tile-header {
background-color: #ED940E;
}
-.tile.success, .label-success {
+.tile.success {
background: #1bbb60;
}
.tile.success > .tile-header {
@@ -476,12 +472,12 @@ text.id {
font-weight: bold;
}
.d3-tip ul {
- padding:0;
- margin:0;
+ padding:0;
+ margin:0;
list-style: none;
-}

+}
.d3-tip ul li {
- font-size: 12px;
+ font-size: 12px;
line-height: 20px;
}
marker {
@@ -538,7 +534,7 @@ ul.legends li.legend{
}
#modal-rebalance .modal-body{
max-height: 450px;
- overflow-y: auto;
+ overflow-y: auto;
}
.loader {
position: fixed;
@@ -546,7 +542,7 @@ ul.legends li.legend{
bottom: 0;
left: 0;
right: 0;
- background: url('../img/loader.gif') rgba(255,255,255,0.75) no-repeat center center;
+ background: url('../images/loader.gif') rgba(255,255,255,0.75) no-repeat center center;
z-index: 9;
}
.inner-loader{
@@ -555,7 +551,7 @@ ul.legends li.legend{
left: 0px;
bottom: 0px;
right: 0px;
- background: url('../img/loader.gif') rgba(255,255,255,0.75) no-repeat center center;
+ background: url('../images/loader.gif') rgba(255,255,255,0.75) no-repeat center center;
}
.searchbar{
margin-top: 15px;
@@ -577,260 +573,7 @@ ul.legends li.legend{
vertical-align: top;
margin-right: 5px;
}
-.searchbar .open > .dropdown-toggle.btn-default:hover,
+.searchbar .open > .dropdown-toggle.btn-default:hover,
.searchbar .open > .dropdown-toggle.btn-default:focus{
border: 1px solid transparent;
-}
-.searchbar .form-group, .searchbar .checkbox {
- margin-top: 0;
- margin-bottom: 0;
-}
-.searchbar .checkbox label {
- font-weight: 600;
- margin-bottom: 5px;
-}
-.topology-table{
- margin-bottom: 0 !important;
-}
-.topology-table a:hover,.panel-heading:hover{
- cursor: pointer;
-}
-.pagination-wrapper{
- width: 100%;
- height: 35px;
- display: block;
- margin-top: 10px;
-}
-.pagination-wrapper > div > p {
- line-height: 35px;
-}
-.pagination-wrapper > ul {
- margin : 0 !important;
-}
-.panel-title > a {
- display: block;
- text-decoration: none;
-}
-.reactable-pagination{
- display: none;
-}
-.pagination > li > a {
- padding: 5px 10px;
- font-size: 12px;
- line-height: 1.5;
-}
-
-.panel-default > .panel-heading{
- background-color: #f3f6f9;
- /*padding: 0 10px;*/
- border-bottom: 1px #bcbcbc solid;
- border-radius: 4px 4px 0px 0px;
-}
-
-.panel-default > .panel-heading h4 {
- margin: 0px;
- font-size: 16px;
- font-weight: 700;
- letter-spacing: 1px;
-}
-/*------------------------------------------------*/
-/* Switch SECTION START*/
-/*------------------------------------------------*/
-.switchWrapper{
- width: 90px;
- height: 30px;
- line-height: 30px;
- overflow: hidden;
- position: relative;
- border-radius: 4px;
- border: 1px solid #ccc;
-}
-.switchSlider{
- width: 135px;
- height: auto;
- position: absolute;
- top:0;
- left:-46px;
- cursor: pointer;
-}
-.switchItemOn{
- width: 45px;
- height: 30px;
- color: #ffffff;
- background-color: #337ab7;
- float: left;
-}
-.switchItemMid{
- width: 44px;
- height: 30px;
- background-color: #ffffff;
- float: left;
-}
-.switchItemOff{
- width: 45px;
- height: 30px;
- color: #000000;
- background-color: #eeeeee;
- float: left;
- clear: right;
-}
-
-.switchSlider.onSlider{
- left : 0 !important;
- transition: all 0.5s ease;
-}
-.switchSlider.offSlider{
- left : -46px !important;
- transition: all 0.5s ease;
-}
-.sliderText{
- text-align: center;
- font-size: 12px;
- line-height: 29px;
-}
-.switchItemOn.graphSwitchOn{
- background-color: #5cb85c;
-}
-
-.switchItemOff.graphSwitchOff{
- background-color: #5bc0de;
- color: #fff;
-}
-/*------------------------------------------------*/
-/* Switch SECTION END*/
-/*------------------------------------------------*/
-.toast-message {
- display: none;
-}
-.switchWrapper.lagSwitchSetting{
- margin-top: 0;
- width: 90px;
- height: 20px;
-}
-.lagSwitchSetting .sliderText{
- line-height: 1.5;
-}
-.box .box-header .box-control span,.box-control span {
- display: inline-block;
- width: 20px;
- height: 20px;
- font-size: 12px;
- line-height: 20px;
- text-align: center;
- margin: 10px 2px;
- border-radius: 50%;
- background-color: #4b4b4b;
- color: rgba(255,255,255,0.75);
-}
-.box-control span {
- margin: 0 2px;
-}
-/*.box .box-header .box-control a i {
- visibility: hidden;
-}
-.box .box-header .box-control:hover a i {
- visibility: visible;
-}*/
-.box .box-header .box-control span.primary, .box-control span.primary {background-color: #1b75bb;}
-/* input range css start here*/
-input[type=range] {
- -webkit-appearance: none;
- width: 100%;
- margin: 6.8px 0;
-}
-input[type=range]:focus {
- outline: none;
-}
-input[type=range]::-webkit-slider-runnable-track {
- width: 100%;
- height: 6.4px;
- cursor: pointer;
- box-shadow: 1px 1px 1px rgba(1, 1, 1, 0), 0px 0px 1px rgba(14, 14, 14, 0);
- background: -moz-linear-gradient(0deg, #cccccc 0%, #ffffff 27%, #ffffff 100%); /* ff3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(73%, #ffffff), color-stop(100%, #cccccc)); /* safari4+,chrome */
- background: -webkit-linear-gradient(0deg, #cccccc 0%, #ffffff 27%, #ffffff 100%); /* safari5.1+,chrome10+ */
- background: -o-linear-gradient(0deg, #cccccc 0%, #ffffff 27%, #ffffff 100%); /* opera 11.10+ */
- background: -ms-linear-gradient(0deg, #cccccc 0%, #ffffff 27%, #ffffff 100%); /* ie10+ */
- background: linear-gradient(0deg, #cccccc 0%, #ffffff 27%, #ffffff 100%); /* w3c */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#cccccc',GradientType=0 ); /* ie6-9 */
- border-radius: 1px;
- border: 0px solid #010101;
-}
-input[type=range]::-webkit-slider-thumb {
- box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0);
- border: 1px solid #186ef7;
- height: 20px;
- width: 20px;
- border-radius: 10px;
- background: #186ef7;
- cursor: pointer;
- -webkit-appearance: none;
- margin-top: -6.8px;
-}
-input[type=range]:focus::-webkit-slider-runnable-track {
- background: -moz-linear-gradient(0deg, #cccccc 10%, #ffffff 27%, #ffffff 100%); /* ff3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(10%, #ffffff), color-stop(73%, #ffffff), color-stop(100%, #cccccc)); /* safari4+,chrome */
- background: -webkit-linear-gradient(0deg, #cccccc 10%, #ffffff 27%, #ffffff 100%); /* safari5.1+,chrome10+ */
- background: -o-linear-gradient(0deg, #cccccc 10%, #ffffff 27%, #ffffff 100%); /* opera 11.10+ */
- background: -ms-linear-gradient(0deg, #cccccc 10%, #ffffff 27%, #ffffff 100%); /* ie10+ */
- background: linear-gradient(0deg, #cccccc 10%, #ffffff 27%, #ffffff 100%); /* w3c */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#cccccc',GradientType=0 ); /* ie6-9 */
-}
-input[type=range]::-moz-range-track {
- width: 100%;
- height: 6.4px;
- cursor: pointer;
- box-shadow: 1px 1px 1px rgba(1, 1, 1, 0), 0px 0px 1px rgba(14, 14, 14, 0);
- background: #c6c6c6;
- border-radius: 1px;
- border: 0px solid #010101;
-}
-input[type=range]::-moz-range-thumb {
- box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0);
- border: 1px solid #186ef7;
- height: 20px;
- width: 20px;
- border-radius: 10px;
- background: #186ef7;
- cursor: pointer;
-}
-input[type=range]::-ms-track {
- width: 100%;
- height: 6.4px;
- cursor: pointer;
- background: transparent;
- border-color: transparent;
- color: transparent;
-}
-input[type=range]::-ms-fill-lower {
- background: #c6c6c6;
- border: 0px solid #010101;
- border-radius: 2px;
- box-shadow: 1px 1px 1px rgba(1, 1, 1, 0), 0px 0px 1px rgba(14, 14, 14, 0);
-}
-input[type=range]::-ms-fill-upper {
- background: #c6c6c6;
- border: 0px solid #010101;
- border-radius: 2px;
- box-shadow: 1px 1px 1px rgba(1, 1, 1, 0), 0px 0px 1px rgba(14, 14, 14, 0);
-}
-input[type=range]::-ms-thumb {
- box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0px 0px 1px rgba(13, 13, 13, 0);
- border: 1px solid #186ef7;
- height: 20px;
- width: 20px;
- border-radius: 10px;
- background: #186ef7;
- cursor: pointer;
- height: 6.4px;
-}
-input[type=range]:focus::-ms-fill-lower {
- background: #c6c6c6;
-}
-input[type=range]:focus::-ms-fill-upper {
- background: #c6c6c6;
-}
-input.editInput{
- width: 68%;
- float: left;
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/.babelrc
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/.babelrc b/contrib/views/storm/src/main/resources/ui/.babelrc
deleted file mode 100644
index b533394..0000000
--- a/contrib/views/storm/src/main/resources/ui/.babelrc
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "presets": [
- ["es2015"],
- "react",
- "stage-0",
- "airbnb"
- ],
- "plugins": [
- "transform-runtime",
- "transform-decorators-legacy",
- "transform-flow-strip-types",
- "transform-es2015-modules-commonjs",
- "transform-class-properties",
- "react-hot-loader/babel",
- "transform-async-to-generator",
- ["babel-root-slash-import", {
- "rootPathSuffix": "./app/scripts"
- }]
- ],
- "env": {
- "production": {
- "plugins": ["transform-react-remove-prop-types", "transform-react-constant-elements","transform-async-to-generator"]
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/.eslintignore.js
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/.eslintignore.js b/contrib/views/storm/src/main/resources/ui/.eslintignore.js
deleted file mode 100644
index 2c4e446..0000000
--- a/contrib/views/storm/src/main/resources/ui/.eslintignore.js
+++ /dev/null
@@ -1,3 +0,0 @@
-node_modules/*
-**/bower_components/*
-**/vendor/*.js
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/.eslintrc.js
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/.eslintrc.js b/contrib/views/storm/src/main/resources/ui/.eslintrc.js
deleted file mode 100644
index 473fe48..0000000
--- a/contrib/views/storm/src/main/resources/ui/.eslintrc.js
+++ /dev/null
@@ -1,58 +0,0 @@
-module.exports = {
- "parser": "babel-eslint",
- "rules": {
- "strict": 0
- },
- "env": {
- "browser": true,
- "es6": true,
- "jquery": true
- },
- "parserOptions": {
- "sourceType": "module"
- },
- "plugins": [
- "header",
- "react"
- ],
- "rules": {
- "header/header": [2, "block", [
- "*",
- " 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.",
- "*"
- ]],
- "comma-dangle": [
- "error",
- "never"
- ],
- "indent": [
- "error",
- 2
- ],
- "linebreak-style": [
- "error",
- "unix"
- ],
- "semi": [
- "error",
- "always"
- ],
- /* Advanced Rules*/
- "no-unexpected-multiline": 2,
- "curly": [2,"all"]
- }
-};
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/BarChart.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/BarChart.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/BarChart.jsx
deleted file mode 100644
index dffd898..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/BarChart.jsx
+++ /dev/null
@@ -1,429 +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.
-**/
-
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
-import d3 from 'd3';
-import d3Tip from 'd3-tip';
-
-export default class BarChart extends Component{
- static propTypes = {
- data: PropTypes.array.isRequired,
- width: PropTypes.number,
- height: PropTypes.number
- }
-
- constructor(props) {
- super(props);
- }
-
- componentDidMount(){
- this.setUpSVG();
- this.initToolTip();
- this.setLayout();
- this.initSets();
- this.barTypeTransition = this.transitionGrouped;
- this.hiddenLayers = [];
- this.drawBars();
- this.drawXAxis();
- this.drawYAxis();
- this.drawTooltip();
- this.drawLegends();
- }
-
- initSets(){
- this.layers = this.dataMapY(this.props.data);
- // this.setMax();
- this.setX();
- this.setY();
- this.colorDomain();
- this.setXAxis();
- this.setYAxis();
- }
-
- setUpSVG(){
- this.svg = d3.select(ReactDOM.findDOMNode(this))
- .attr('width', this.props.width+"px")
- .attr('height', this.props.height+50+"px");
- // .attr("viewBox", "-46 -5 " + (this.props.width+82) + " " + (this.props.height+28) );
-
- this.container = this.svg.append("g")
- .attr('class', 'svg-container')
- .attr("transform", "translate(50,10)");
-
- this.tipcontainer = this.svg.append('g').classed('tip-g', true)
- .attr("transform", "translate(" + 40 + "," + 0 + ")");
-
- this.tipcontainer.append('g').classed('tipLine-g', true).append('line').classed('tipline', true)
- .style('stroke', '#aaa')
- .style('visibility', 'hidden')
- // .style('shape-rendering', 'crispEdges')
- .attr('x1', 0).attr('x2', 0).attr('y1', 0).attr('y2', this.props.height);
- }
-
- initToolTip() {
- let self = this;
- this.tip = d3Tip()
- .attr('class', 'd3-tip')
- .offset([-10, 0])
- .html(function(d) {
- return self.toolTipHtml.call(self, d);
- });
- this.svg.call(this.tip);
- // const container = document.getElementById('app_container');
- // container.append($('body > .d3-tip'));
- }
-
- setMax() {
- this.yGroupMax = d3.max(this.layers, function(layer) {
- return d3.max(layer, function(d) {
- return d.y;
- });
- });
- this.yGroupMin = d3.min(this.layers, function(layer) {
- return d3.min(layer, function(d) {
- return d.y;
- });
- });
- this.yStackMax = d3.max(this.layers, function(layer) {
- return d3.max(layer, function(d) {
- return d.y0 + d.y;
- });
- });
- this.yStackMin = d3.min(this.layers, function(layer) {
- return d3.min(layer, function(d) {
- return d3.min([d.y0, d.y]);
- });
- });
- }
-
- setX() {
- let self = this;
- this.x = d3.scale.ordinal()
- .domain(self.layers[0].map(function(d) {
- return d.x;
- }))
- .rangeRoundBands([0, this.props.width], 0.08);
- }
-
- setY() {
- this.y = d3.scale.linear()
- .domain([this.yStackMin, this.yStackMax])
- .range([this.props.height, 0]);
- }
-
- setXAxis() {
- this.xAxis = d3.svg.axis().scale(this.x).orient("bottom");
- }
-
- setYAxis() {
- let formatValue = d3.format('.2s');
- this.yAxis = d3.svg
- .axis()
- .scale(this.y)
- .orient("left")
- .tickFormat(function(d){return formatValue(d);});
- }
-
- drawXAxis(xAxis, container, height) {
- let xA = xAxis || this.xAxis,
- containor = container || this.container,
- hght = height || this.props.height;
-
- this.xAxisGrp = containor['xAxisEl'] = containor.append("g")
- .attr("class", "x axis")
- .attr("transform", "translate(0," + hght + ")")
- .call(xA)
- .selectAll(".tick text")
- .call(this.wrap, this.x.rangeBand());
- }
-
- wrap(text, width) {
- text.each(function() {
- let text = d3.select(this),
- words = text.text().split(/-+/).reverse(),
- word,
- line = [],
- lineNumber = 0,
- lineHeight = 1.1, // ems
- y = text.attr("y"),
- dy = parseFloat(text.attr("dy")),
- tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
-
- //Hack to show hidden div to find getComputedTextLength
- // $('#lag-graph').css({visibility: 'hidden', display: 'block', position: 'absolute'});
-
- while (word = words.pop()) {
- line.push(word);
- tspan.text(line.join(" "));
- if (tspan.node().getComputedTextLength() > width) {
- line.pop();
- tspan.text(line.join(" "));
- line = [word];
- tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
- }
- }
- // $('#lag-graph').css({visibility: '', display: 'none', position: ''});
- });
- }
-
- drawYAxis(x) {
- let yAxis = this.yAxis;
- this.yAxisGrp = this.container.append("g")
- .attr("class", "y axis");
- this.yAxisGrp.ticks = this.yAxisGrp.call(yAxis);
- this.yAxisGrp.append('text')
- .text(this.props.yAttr[0].toUpperCase() + this.props.yAttr.substr(1,this.props.yAttr.length)).attr("text-anchor", "end")
- .attr("y", 6)
- .attr("dy", ".75em")
- .attr("transform", "rotate(-90)");
- }
-
- dataMapY(data) {
- let self = this;
- let keys = d3.keys(data[0]).filter(function(key) {
- return key !== self.props.xAttr;
- });
- let layers = this.stack(keys.map(function(yAttr) {
- return data.map(function(d) {
- return {
- x: d[self.props.xAttr],
- y: d[yAttr],
- type: yAttr
- };
- });
- }));
- let allLayers = layers.allLayers = [];
- layers.forEach(function(d) {
- allLayers.push(d);
- });
- return layers;
- }
-
- setLayout() {
- let self = this;
- this.stack = d3.layout.stack();
- }
-
- colorDomain() {
- let self = this;
- this.color = d3.scale.ordinal()
- .range(["#b9cde5", "#1B76BB"]);
- // this.color = d3.scale.category20c();
- // this.color.domain(d3.keys(this.props.data[0]).filter(function(key) {
- // return key !== self.props.xAttr;
- // }));
- }
-
- drawBars() {
- let self = this;
-
- this.layers_g = this.container.selectAll(".barLayer")
- .data(this.layers);
-
- this.layers_g
- .exit()
- .remove();
-
- this.layers_g
- .enter().append("g")
- .attr("class", "barLayer")
- .style("fill", function(d, i) {
- return self.color(d[0].type);
- });
-
- this.rect = this.layers_g.selectAll("rect")
- .data(function(d) {
- return d;
- });
-
- this.rect
- .exit()
- .remove();
-
- this.rect
- .enter().append("rect")
- .attr("x", function(d) {
- return self.x(d.x);
- })
- .attr("y", function(d) {
- return self.props.height;
- })
- .attr("width", function(d) {
- return self.x.rangeBand();
- })
- .classed("visible", true)
- .attr("height", function(d) {
- return 0;
- });
-
- this.barTypeTransition();
- }
-
- transitionGrouped() {
- let x = this.x,
- y = this.y,
- height = this.props.height,
- n = this.layers.length;
- this.setMax();
- let yMin = this.yGroupMin < 0 ? this.yGroupMin : 0;
- this.y.domain([yMin, this.yGroupMax]);
-
- let barWidth = (x.rangeBand() / n > 25) ? 25 : x.rangeBand() / n;
- let xArr = new Array(n);
- this.layers_g.selectAll('rect.visible')
- .attr("x", function(d, i, j) {
- if (xArr[i] == undefined) {
- xArr[i] = x(d.x) + (x.rangeBand() / 2) - (n / 2 * barWidth);
- } else {
- xArr[i] += barWidth;
- }
- return xArr[i];
- })
- .attr("width", barWidth)
- .transition().duration(500)
- .attr("y", function(d) {
- let _y = y(d.y);
- if (d.y < 0){
- _y = y(d.y) - (height - y(0));
- }
- return _y;
- })
- .attr("height", function(d) {
- return (height - y(Math.abs(d.y))) - (height - y(0));
- });
- this.container.select(".y.axis").transition().duration(500).call(this.yAxis);
- }
-
- transitionStacked() {
- this.stack(this.layers);
- let x = this.x,
- y = this.y,
- height = this.props.height,
- self = this,
- n = this.layers.length;
- this.setMax();
- this.y.domain([this.yStackMin, this.yStackMax]);
-
- let barWidth = (x.rangeBand() / n > 25) ? 25 : x.rangeBand() / n;
- let xArr = new Array(n);
- this.layers_g.selectAll('rect.visible').transition().duration(500)
- .attr("y", function(d) {
- let _y = y(d.y0 + d.y);
- if (d.y < 0){
- _y = y(d.y) - Math.abs(y(d.y0) - y(d.y0 + d.y));
- }
- return _y;
- })
- .attr("height", function(d) {
- return Math.abs(y(d.y0) - y(d.y0 + d.y));
- })
- .attr("x", function(d, i, j) {
- xArr[i] = x(d.x) + (x.rangeBand() / 2) - (barWidth / 2);
- return xArr[i];
- })
- .attr("width", barWidth);
- this.container.select(".y.axis").transition().duration(500).call(this.yAxis);
- }
-
- drawTooltip() {
- let self = this;
- let x = this.x.rangeBand ? this.x : d3.scale.ordinal()
- .domain(self.data.map(function(d) {
- return d[self.props.xAttr];
- }))
- .rangeRoundBands([0, this.props.width]);
-
- let tipline = this.tipcontainer.select('.tipline');
-
- this.tipcontainer.append('g').classed('tipRect-g', true).selectAll(".tipRect")
- .data(this.props.data)
- .enter().append("rect")
- .attr("class", "tipRect")
- .style('opacity', '0')
- .attr("x", function(d) {
- return self.x(d[self.props.xAttr]);
- })
- .attr("width", function() {
- return x.rangeBand();
- })
- .attr("y", function(d) {
- return 0;
- })
- .attr("height", function(d) {
- return self.props.height;
- })
- .on('mouseover', function(d) {
- let x1 = parseInt(d3.select(this).attr('x')) + parseInt((x.rangeBand() / 2));
- tipline.attr('x1', x1).attr('x2', x1);
- tipline.style('visibility', 'visible');
- return self.tip.show(d,this);
- })
- .on('mouseout', function(d) {
- tipline.style('visibility', 'hidden');
- return self.tip.hide(d,this);
- });
- }
-
- toolTipHtml(d) {
- let self = this;
- let html = d[self.props.xAttr] + '<table><tbody>';
- _.each(d, function(val, key) {
- if (key != self.props.xAttr){
- html += '<tr><td>' + key + ' </td><td> ' + val + '</td></tr>';
- }
- });
- html += '</tbody></table>';
- return html;
- }
-
- drawLegends() {
- let self = this;
- let legends = this.legendsEl = document.createElement('ul');
- legends = d3.select(legends)
- .attr('class', 'legends')
- .style('list-style', 'none');
-
- let legend = legends.selectAll('.legend')
- .data(this.color.domain())
- .enter()
- .append('li')
- .attr('class', 'legend');
-
- legend.append('div')
- .style('width', '10px')
- .style('height', '10px')
- .style('display', 'inline-block')
- .style('background-color', function(d) {
- return self.color(d);
- });
-
- legend.append('span')
- .style('padding', '4px 0 4px 4px')
- .text(function(d) {
- return d;
- });
- }
-
- render() {
- return (
- <svg></svg>
- );
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/Breadcrumbs.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/Breadcrumbs.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/Breadcrumbs.jsx
deleted file mode 100644
index e4926ab..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/Breadcrumbs.jsx
+++ /dev/null
@@ -1,45 +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.
-**/
-
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import ReactDom from 'react-dom';
-
-export default class Breadcrumbs extends Component{
- static propTypes = {
- links: PropTypes.array.isRequired
- }
- render() {
- return (
- <ol id="breadcrumb">
- {this.renderLinks()}
- </ol>
- );
- }
- renderLinks() {
- var links = [];
- for(var i = 0; i < this.props.links.length; i++){
- var object = this.props.links[i];
- if(object.link === '#/'){
- object.title = <i className="fa fa-home"></i>;
- }
- links.push(<li key={i}><a href={object.link}>{object.title}</a></li>);
- }
- return links;
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonNotification.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonNotification.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonNotification.jsx
deleted file mode 100644
index 34e402c..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonNotification.jsx
+++ /dev/null
@@ -1,69 +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.
-**/
-
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import {notifyTextLimit} from '../utils/Constants';
-
-class CommonNotification extends Component {
- constructor(props) {
- super(props);
- this.state = {
- data: false,
- text: "Read more"
- };
- }
- showMore = () => {
- if (this.state.text === "Read more") {
- this.setState({text: "Hide", data: true});
- } else {
- this.setState({text: "Read more", data: false});
- }
- }
-
- render() {
- /* flag value error, info, sucess */
- const {text, data} = this.state;
- const {flag, content} = this.props;
- const initial = content.substr(0, notifyTextLimit);
- const moreText = content.substr(notifyTextLimit);
- const readMoreTag = <a href="javascript:void(0)" onClick={this.showMore}>{text}</a>;
- return (
- <div>
- {initial}
- {(data)
- ? moreText
- : null
-}
- <div>
- {(flag === 'error' && moreText.length > 0)
- ? readMoreTag
- : null
-}
- </div>
- </div>
- );
- }
-}
-
-export default CommonNotification;
-
-CommonNotification.propTypes = {
- flag: PropTypes.string.isRequired,
- content: PropTypes.string
-};
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonPagination.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonPagination.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonPagination.jsx
deleted file mode 100644
index 5128a09..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonPagination.jsx
+++ /dev/null
@@ -1,56 +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.
-**/
-
-import React, {Component} from 'react';
-import _ from 'lodash';
-import {Pagination} from 'react-bootstrap';
-
-export default class CommonPagination extends Component{
- constructor(props){
- super(props);
- }
-
- handleSelect = (eventKey) => {
- this.props.callBackFunction(eventKey,this.props.tableName);
- }
-
- render(){
- const {activePage,pageSize,filteredEntities} = this.props;
- const totalPages = Math.ceil(filteredEntities.length / pageSize);
-
- return(
- <div className="pagination-wrapper">
- <div className="pull-left">
- <span>{`Showing ${activePage > 1 ? (activePage-1)*pageSize : activePage } to ${activePage*pageSize > filteredEntities.length ? filteredEntities.length : (activePage*pageSize)} of ${filteredEntities.length} entries`}</span>
- </div>
- <Pagination
- className={`${filteredEntities.length === 0? 'hidden':'shown pull-right'}`}
- prev={false}
- next={false}
- first
- last
- ellipsis
- items={totalPages}
- maxButtons={5}
- activePage={activePage}
- onSelect={this.handleSelect}>
- </Pagination>
- </div>
- );
- }
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonSwitchComponent.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonSwitchComponent.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonSwitchComponent.jsx
deleted file mode 100644
index 804f51e..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonSwitchComponent.jsx
+++ /dev/null
@@ -1,41 +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.
-**/
-
-import React, {Component} from 'react';
-
-export default class CommonSwitchComponent extends Component {
- render(){
- const {switchCallBack,checked,textON,textOFF,KYC} = this.props;
- let switchId = "switch-"+((Math.random())*100).toFixed(0);
- return (
- <div className={`switchWrapper ${!!KYC ? 'lagSwitchSetting pull-right' : ''}`}>
- <span className={`switchSlider ${checked ? 'onSlider' : 'offSlider'}`} onClick={switchCallBack}>
- <span className={`switchItemOn sliderText ${!!KYC ? 'graphSwitchOn' : ''}`}>{textON}</span>
- <span className="switchItemMid"></span>
- <span className={`switchItemOff sliderText ${!!KYC ? 'graphSwitchOff' : ''}`}>{textOFF}</span>
- </span>
- </div>
-
- );
- }
-}
-
-CommonSwitchComponent.defaultProps = {
- textON : "ON",
- textOFF : "OFF"
-};
http://git-wip-us.apache.org/repos/asf/ambari/blob/03735c99/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonWindowPanel.jsx
----------------------------------------------------------------------
diff --git a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonWindowPanel.jsx b/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonWindowPanel.jsx
deleted file mode 100644
index 0f8130f..0000000
--- a/contrib/views/storm/src/main/resources/ui/app/scripts/components/CommonWindowPanel.jsx
+++ /dev/null
@@ -1,99 +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.
-**/
-
-import React, {Component} from 'react';
-import Select from 'react-select';
-import CommonSwitchComponent from './CommonSwitchComponent';
-import {OverlayTrigger, Tooltip} from 'react-bootstrap';
-
-export default class CommonWindowPanel extends Component{
- constructor(props){
- super(props);
- }
-
- windowChange = (obj) => {
- this.props.handleWindowChange(obj);
- }
-
- commonToggleChange = (params) => {
- this.props.toggleSystem(params);
- }
-
- commonTopologyActionHandler = (action) => {
- this.props.handleTopologyAction(action);
- }
-
- render(){
- const {selectedWindowKey,windowOptions,systemFlag,debugFlag,handleLogLevel,topologyStatus,KYC,handleProfiling} = this.props;
- return(
- <div className="form-group no-margin">
- <label className="col-sm-1 control-label">Window</label>
- <div className="col-sm-2">
- <Select value={selectedWindowKey} options={windowOptions} onChange={this.windowChange.bind(this)} valueKey="label" labelKey="label" clearable={false}/>
- </div>
- <label className="col-sm-2 control-label">System Summary</label>
- <div className="col-sm-2">
- <CommonSwitchComponent checked={systemFlag} switchCallBack={this.commonToggleChange.bind(this,'systemFlag')}/>
- </div>
- <label className="col-sm-1 control-label">Debug</label>
- <div className="col-sm-1">
- <CommonSwitchComponent checked={debugFlag} switchCallBack={this.commonToggleChange.bind(this,'debugFlag')}/>
- </div>
- <div className="col-sm-3 text-right">
- <div className="btn-group" role="group">
- {
- KYC === 'detailView'
- ? [ <OverlayTrigger key={1} placement="top" overlay={<Tooltip id="tooltip1">Activate</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={this.commonTopologyActionHandler.bind(this,'activate')} disabled={topologyStatus === 'ACTIVE' ? "disabled" : null}>
- <i className="fa fa-play"></i>
- </button>
- </OverlayTrigger>,
- <OverlayTrigger key={2} placement="top" overlay={<Tooltip id="tooltip1">Deactivate</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={this.commonTopologyActionHandler.bind(this,'deactivate')} disabled={topologyStatus === 'INACTIVE' ? "disabled" : null}>
- <i className="fa fa-stop"></i>
- </button>
- </OverlayTrigger>,
- <OverlayTrigger key={3} placement="top" overlay={<Tooltip id="tooltip1">Rebalance</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={this.commonTopologyActionHandler.bind(this,'rebalance')} disabled={topologyStatus === 'REBALANCING' ? "disabled" : null}>
- <i className="fa fa-balance-scale"></i>
- </button>
- </OverlayTrigger>,
- <OverlayTrigger key={4} placement="top" overlay={<Tooltip id="tooltip1">Kill</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={this.commonTopologyActionHandler.bind(this,'kill')} disabled={topologyStatus === 'KILLED' ? "disabled" : null}>
- <i className="fa fa-ban"></i>
- </button>
- </OverlayTrigger>,
- <OverlayTrigger key={5} placement="top" overlay={<Tooltip id="tooltip1">Change Log Level</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={handleLogLevel}>
- <i className="fa fa-file-o"></i>
- </button>
- </OverlayTrigger>
- ]
- : <OverlayTrigger placement="top" overlay={<Tooltip id="tooltip1">Profiling & Debugging</Tooltip>}>
- <button type="button" className="btn btn-primary" onClick={handleProfiling}>
- <i className="fa fa-cogs"></i>
- </button>
- </OverlayTrigger>
-
- }
- </div>
- </div>
- </div>
- );
- }
-}