Ver Fonte

AMBARI-11954. Ambari storm view fix for html page and added loading gif (Sriharsha Chintalapani via srimanth)

Srimanth Gunturi há 10 anos atrás
pai
commit
41fe3e89f3
20 ficheiros alterados com 1028 adições e 212 exclusões
  1. 1 0
      contrib/views/pom.xml
  2. 0 0
      contrib/views/storm/src/main/resources/libs/bower/bootstrap/css/bootstrap.min.css
  3. 0 0
      contrib/views/storm/src/main/resources/libs/bower/jquery-ui/css/jquery-ui.min.css
  4. 655 0
      contrib/views/storm/src/main/resources/libs/bower/jquery-ui/js/jquery-ui-slider.js
  5. 2 1
      contrib/views/storm/src/main/resources/scripts/globalize/message/en.js
  6. 8 1
      contrib/views/storm/src/main/resources/scripts/main.js
  7. 7 6
      contrib/views/storm/src/main/resources/scripts/router/Router.js
  8. 137 56
      contrib/views/storm/src/main/resources/scripts/utils/Overrides.js
  9. 10 38
      contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js
  10. 54 9
      contrib/views/storm/src/main/resources/scripts/views/Topology/RebalanceForm.js
  11. 25 23
      contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyDetail.js
  12. 20 19
      contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js
  13. 27 7
      contrib/views/storm/src/main/resources/scripts/views/site/Header.js
  14. 34 18
      contrib/views/storm/src/main/resources/styles/default.css
  15. 4 4
      contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html
  16. 6 0
      contrib/views/storm/src/main/resources/templates/site/header.html
  17. 26 0
      contrib/views/storm/src/main/resources/templates/topology/rebalanceForm.html
  18. 6 6
      contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html
  19. 4 22
      contrib/views/storm/src/main/resources/templates/topology/topologyForm.html
  20. 2 2
      contrib/views/storm/src/main/resources/templates/topology/topologySummary.html

+ 1 - 0
contrib/views/pom.xml

@@ -40,6 +40,7 @@
     <module>capacity-scheduler</module>
     <module>tez</module>
     <module>utils</module>
+    <module>storm</module>
   </modules>
   <build>
     <pluginManagement>

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
contrib/views/storm/src/main/resources/libs/bower/bootstrap/css/bootstrap.min.css


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
contrib/views/storm/src/main/resources/libs/bower/jquery-ui/css/jquery-ui.min.css


+ 655 - 0
contrib/views/storm/src/main/resources/libs/bower/jquery-ui/js/jquery-ui-slider.js

@@ -0,0 +1,655 @@
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+	version: "1.10.3",
+	widgetEventPrefix: "slide",
+
+	options: {
+		animate: false,
+		distance: 0,
+		max: 100,
+		min: 0,
+		orientation: "horizontal",
+		range: false,
+		step: 1,
+		value: 0,
+		values: null,
+
+		// callbacks
+		change: null,
+		slide: null,
+		start: null,
+		stop: null
+	},
+
+	_create: function() {
+		this._keySliding = false;
+		this._mouseSliding = false;
+		this._animateOff = true;
+		this._handleIndex = null;
+		this._detectOrientation();
+		this._mouseInit();
+
+		this.element
+			.addClass( "ui-slider" +
+				" ui-slider-" + this.orientation +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all");
+
+		this._refresh();
+		this._setOption( "disabled", this.options.disabled );
+
+		this._animateOff = false;
+	},
+
+	_refresh: function() {
+		this._createRange();
+		this._createHandles();
+		this._setupEvents();
+		this._refreshValue();
+	},
+
+	_createHandles: function() {
+		var i, handleCount,
+			options = this.options,
+			existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+			handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+			handles = [];
+
+		handleCount = ( options.values && options.values.length ) || 1;
+
+		if ( existingHandles.length > handleCount ) {
+			existingHandles.slice( handleCount ).remove();
+			existingHandles = existingHandles.slice( 0, handleCount );
+		}
+
+		for ( i = existingHandles.length; i < handleCount; i++ ) {
+			handles.push( handle );
+		}
+
+		this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+		this.handle = this.handles.eq( 0 );
+
+		this.handles.each(function( i ) {
+			$( this ).data( "ui-slider-handle-index", i );
+		});
+	},
+
+	_createRange: function() {
+		var options = this.options,
+			classes = "";
+
+		if ( options.range ) {
+			if ( options.range === true ) {
+				if ( !options.values ) {
+					options.values = [ this._valueMin(), this._valueMin() ];
+				} else if ( options.values.length && options.values.length !== 2 ) {
+					options.values = [ options.values[0], options.values[0] ];
+				} else if ( $.isArray( options.values ) ) {
+					options.values = options.values.slice(0);
+				}
+			}
+
+			if ( !this.range || !this.range.length ) {
+				this.range = $( "<div></div>" )
+					.appendTo( this.element );
+
+				classes = "ui-slider-range" +
+				// note: this isn't the most fittingly semantic framework class for this element,
+				// but worked best visually with a variety of themes
+				" ui-widget-header ui-corner-all";
+			} else {
+				this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+					// Handle range switching from true to min/max
+					.css({
+						"left": "",
+						"bottom": ""
+					});
+			}
+
+			this.range.addClass( classes +
+				( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+		} else {
+			this.range = $([]);
+		}
+	},
+
+	_setupEvents: function() {
+		var elements = this.handles.add( this.range ).filter( "a" );
+		this._off( elements );
+		this._on( elements, this._handleEvents );
+		this._hoverable( elements );
+		this._focusable( elements );
+	},
+
+	_destroy: function() {
+		this.handles.remove();
+		this.range.remove();
+
+		this.element
+			.removeClass( "ui-slider" +
+				" ui-slider-horizontal" +
+				" ui-slider-vertical" +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all" );
+
+		this._mouseDestroy();
+	},
+
+	_mouseCapture: function( event ) {
+		var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+			that = this,
+			o = this.options;
+
+		if ( o.disabled ) {
+			return false;
+		}
+
+		this.elementSize = {
+			width: this.element.outerWidth(),
+			height: this.element.outerHeight()
+		};
+		this.elementOffset = this.element.offset();
+
+		position = { x: event.pageX, y: event.pageY };
+		normValue = this._normValueFromMouse( position );
+		distance = this._valueMax() - this._valueMin() + 1;
+		this.handles.each(function( i ) {
+			var thisDistance = Math.abs( normValue - that.values(i) );
+			if (( distance > thisDistance ) ||
+				( distance === thisDistance &&
+					(i === that._lastChangedValue || that.values(i) === o.min ))) {
+				distance = thisDistance;
+				closestHandle = $( this );
+				index = i;
+			}
+		});
+
+		allowed = this._start( event, index );
+		if ( allowed === false ) {
+			return false;
+		}
+		this._mouseSliding = true;
+
+		this._handleIndex = index;
+
+		closestHandle
+			.addClass( "ui-state-active" )
+			.focus();
+
+		offset = closestHandle.offset();
+		mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+			top: event.pageY - offset.top -
+				( closestHandle.height() / 2 ) -
+				( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+				( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+				( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+		};
+
+		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+			this._slide( event, index, normValue );
+		}
+		this._animateOff = true;
+		return true;
+	},
+
+	_mouseStart: function() {
+		return true;
+	},
+
+	_mouseDrag: function( event ) {
+		var position = { x: event.pageX, y: event.pageY },
+			normValue = this._normValueFromMouse( position );
+
+		this._slide( event, this._handleIndex, normValue );
+
+		return false;
+	},
+
+	_mouseStop: function( event ) {
+		this.handles.removeClass( "ui-state-active" );
+		this._mouseSliding = false;
+
+		this._stop( event, this._handleIndex );
+		this._change( event, this._handleIndex );
+
+		this._handleIndex = null;
+		this._clickOffset = null;
+		this._animateOff = false;
+
+		return false;
+	},
+
+	_detectOrientation: function() {
+		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+	},
+
+	_normValueFromMouse: function( position ) {
+		var pixelTotal,
+			pixelMouse,
+			percentMouse,
+			valueTotal,
+			valueMouse;
+
+		if ( this.orientation === "horizontal" ) {
+			pixelTotal = this.elementSize.width;
+			pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+		} else {
+			pixelTotal = this.elementSize.height;
+			pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+		}
+
+		percentMouse = ( pixelMouse / pixelTotal );
+		if ( percentMouse > 1 ) {
+			percentMouse = 1;
+		}
+		if ( percentMouse < 0 ) {
+			percentMouse = 0;
+		}
+		if ( this.orientation === "vertical" ) {
+			percentMouse = 1 - percentMouse;
+		}
+
+		valueTotal = this._valueMax() - this._valueMin();
+		valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+		return this._trimAlignValue( valueMouse );
+	},
+
+	_start: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+		return this._trigger( "start", event, uiHash );
+	},
+
+	_slide: function( event, index, newVal ) {
+		var otherVal,
+			newValues,
+			allowed;
+
+		if ( this.options.values && this.options.values.length ) {
+			otherVal = this.values( index ? 0 : 1 );
+
+			if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+					( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+				) {
+				newVal = otherVal;
+			}
+
+			if ( newVal !== this.values( index ) ) {
+				newValues = this.values();
+				newValues[ index ] = newVal;
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal,
+					values: newValues
+				} );
+				otherVal = this.values( index ? 0 : 1 );
+				if ( allowed !== false ) {
+					this.values( index, newVal, true );
+				}
+			}
+		} else {
+			if ( newVal !== this.value() ) {
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal
+				} );
+				if ( allowed !== false ) {
+					this.value( newVal );
+				}
+			}
+		}
+	},
+
+	_stop: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+
+		this._trigger( "stop", event, uiHash );
+	},
+
+	_change: function( event, index ) {
+		if ( !this._keySliding && !this._mouseSliding ) {
+			var uiHash = {
+				handle: this.handles[ index ],
+				value: this.value()
+			};
+			if ( this.options.values && this.options.values.length ) {
+				uiHash.value = this.values( index );
+				uiHash.values = this.values();
+			}
+
+			//store the last changed value index for reference when handles overlap
+			this._lastChangedValue = index;
+
+			this._trigger( "change", event, uiHash );
+		}
+	},
+
+	value: function( newValue ) {
+		if ( arguments.length ) {
+			this.options.value = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, 0 );
+			return;
+		}
+
+		return this._value();
+	},
+
+	values: function( index, newValue ) {
+		var vals,
+			newValues,
+			i;
+
+		if ( arguments.length > 1 ) {
+			this.options.values[ index ] = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, index );
+			return;
+		}
+
+		if ( arguments.length ) {
+			if ( $.isArray( arguments[ 0 ] ) ) {
+				vals = this.options.values;
+				newValues = arguments[ 0 ];
+				for ( i = 0; i < vals.length; i += 1 ) {
+					vals[ i ] = this._trimAlignValue( newValues[ i ] );
+					this._change( null, i );
+				}
+				this._refreshValue();
+			} else {
+				if ( this.options.values && this.options.values.length ) {
+					return this._values( index );
+				} else {
+					return this.value();
+				}
+			}
+		} else {
+			return this._values();
+		}
+	},
+
+	_setOption: function( key, value ) {
+		var i,
+			valsLength = 0;
+
+		if ( key === "range" && this.options.range === true ) {
+			if ( value === "min" ) {
+				this.options.value = this._values( 0 );
+				this.options.values = null;
+			} else if ( value === "max" ) {
+				this.options.value = this._values( this.options.values.length-1 );
+				this.options.values = null;
+			}
+		}
+
+		if ( $.isArray( this.options.values ) ) {
+			valsLength = this.options.values.length;
+		}
+
+		$.Widget.prototype._setOption.apply( this, arguments );
+
+		switch ( key ) {
+			case "orientation":
+				this._detectOrientation();
+				this.element
+					.removeClass( "ui-slider-horizontal ui-slider-vertical" )
+					.addClass( "ui-slider-" + this.orientation );
+				this._refreshValue();
+				break;
+			case "value":
+				this._animateOff = true;
+				this._refreshValue();
+				this._change( null, 0 );
+				this._animateOff = false;
+				break;
+			case "values":
+				this._animateOff = true;
+				this._refreshValue();
+				for ( i = 0; i < valsLength; i += 1 ) {
+					this._change( null, i );
+				}
+				this._animateOff = false;
+				break;
+			case "min":
+			case "max":
+				this._animateOff = true;
+				this._refreshValue();
+				this._animateOff = false;
+				break;
+			case "range":
+				this._animateOff = true;
+				this._refresh();
+				this._animateOff = false;
+				break;
+		}
+	},
+
+	//internal value getter
+	// _value() returns value trimmed by min and max, aligned by step
+	_value: function() {
+		var val = this.options.value;
+		val = this._trimAlignValue( val );
+
+		return val;
+	},
+
+	//internal values getter
+	// _values() returns array of values trimmed by min and max, aligned by step
+	// _values( index ) returns single value trimmed by min and max, aligned by step
+	_values: function( index ) {
+		var val,
+			vals,
+			i;
+
+		if ( arguments.length ) {
+			val = this.options.values[ index ];
+			val = this._trimAlignValue( val );
+
+			return val;
+		} else if ( this.options.values && this.options.values.length ) {
+			// .slice() creates a copy of the array
+			// this copy gets trimmed by min and max and then returned
+			vals = this.options.values.slice();
+			for ( i = 0; i < vals.length; i+= 1) {
+				vals[ i ] = this._trimAlignValue( vals[ i ] );
+			}
+
+			return vals;
+		} else {
+			return [];
+		}
+	},
+
+	// returns the step-aligned value that val is closest to, between (inclusive) min and max
+	_trimAlignValue: function( val ) {
+		if ( val <= this._valueMin() ) {
+			return this._valueMin();
+		}
+		if ( val >= this._valueMax() ) {
+			return this._valueMax();
+		}
+		var step = ( this.options.step > 0 ) ? this.options.step : 1,
+			valModStep = (val - this._valueMin()) % step,
+			alignValue = val - valModStep;
+
+		if ( Math.abs(valModStep) * 2 >= step ) {
+			alignValue += ( valModStep > 0 ) ? step : ( -step );
+		}
+
+		// Since JavaScript has problems with large floats, round
+		// the final value to 5 digits after the decimal point (see #4124)
+		return parseFloat( alignValue.toFixed(5) );
+	},
+
+	_valueMin: function() {
+		return this.options.min;
+	},
+
+	_valueMax: function() {
+		return this.options.max;
+	},
+
+	_refreshValue: function() {
+		var lastValPercent, valPercent, value, valueMin, valueMax,
+			oRange = this.options.range,
+			o = this.options,
+			that = this,
+			animate = ( !this._animateOff ) ? o.animate : false,
+			_set = {};
+
+		if ( this.options.values && this.options.values.length ) {
+			this.handles.each(function( i ) {
+				valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+				_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+				if ( that.options.range === true ) {
+					if ( that.orientation === "horizontal" ) {
+						if ( i === 0 ) {
+							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					} else {
+						if ( i === 0 ) {
+							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					}
+				}
+				lastValPercent = valPercent;
+			});
+		} else {
+			value = this.value();
+			valueMin = this._valueMin();
+			valueMax = this._valueMax();
+			valPercent = ( valueMax !== valueMin ) ?
+					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+					0;
+			_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+			if ( oRange === "min" && this.orientation === "horizontal" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "horizontal" ) {
+				this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+			if ( oRange === "min" && this.orientation === "vertical" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "vertical" ) {
+				this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+		}
+	},
+
+	_handleEvents: {
+		keydown: function( event ) {
+			/*jshint maxcomplexity:25*/
+			var allowed, curVal, newVal, step,
+				index = $( event.target ).data( "ui-slider-handle-index" );
+
+			switch ( event.keyCode ) {
+				case $.ui.keyCode.HOME:
+				case $.ui.keyCode.END:
+				case $.ui.keyCode.PAGE_UP:
+				case $.ui.keyCode.PAGE_DOWN:
+				case $.ui.keyCode.UP:
+				case $.ui.keyCode.RIGHT:
+				case $.ui.keyCode.DOWN:
+				case $.ui.keyCode.LEFT:
+					event.preventDefault();
+					if ( !this._keySliding ) {
+						this._keySliding = true;
+						$( event.target ).addClass( "ui-state-active" );
+						allowed = this._start( event, index );
+						if ( allowed === false ) {
+							return;
+						}
+					}
+					break;
+			}
+
+			step = this.options.step;
+			if ( this.options.values && this.options.values.length ) {
+				curVal = newVal = this.values( index );
+			} else {
+				curVal = newVal = this.value();
+			}
+
+			switch ( event.keyCode ) {
+				case $.ui.keyCode.HOME:
+					newVal = this._valueMin();
+					break;
+				case $.ui.keyCode.END:
+					newVal = this._valueMax();
+					break;
+				case $.ui.keyCode.PAGE_UP:
+					newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
+					break;
+				case $.ui.keyCode.PAGE_DOWN:
+					newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
+					break;
+				case $.ui.keyCode.UP:
+				case $.ui.keyCode.RIGHT:
+					if ( curVal === this._valueMax() ) {
+						return;
+					}
+					newVal = this._trimAlignValue( curVal + step );
+					break;
+				case $.ui.keyCode.DOWN:
+				case $.ui.keyCode.LEFT:
+					if ( curVal === this._valueMin() ) {
+						return;
+					}
+					newVal = this._trimAlignValue( curVal - step );
+					break;
+			}
+
+			this._slide( event, index, newVal );
+		},
+		click: function( event ) {
+			event.preventDefault();
+		},
+		keyup: function( event ) {
+			var index = $( event.target ).data( "ui-slider-handle-index" );
+
+			if ( this._keySliding ) {
+				this._keySliding = false;
+				this._stop( event, index );
+				this._change( event, index );
+				$( event.target ).removeClass( "ui-state-active" );
+			}
+		}
+	}
+
+});}(jQuery));

+ 2 - 1
contrib/views/storm/src/main/resources/scripts/globalize/message/en.js

@@ -98,7 +98,8 @@
           cancel: 'Cancel',
           save: 'Save',
           yes: 'Yes',
-          no: 'No'
+          no: 'No',
+          apply: 'Apply'
         },
         h: {
           topologies: 'Topologies',

+ 8 - 1
contrib/views/storm/src/main/resources/scripts/main.js

@@ -80,6 +80,9 @@ require.config({
     'jquery.ui.widget': {
       deps: ['jquery']
     },
+    'jquery-ui-slider': {
+      deps: ['jquery', 'jquery-ui', 'jquery.ui.widget']
+    },
     globalize: {
       exports: 'Globalize'
     },
@@ -115,6 +118,7 @@ require.config({
     'backgrid': '../libs/bower/backgrid/js/backgrid',
     'jquery-ui': '../libs/bower/jquery-ui/js/jquery-ui-1.10.3.custom',
     'jquery.ui.widget': '../libs/bower/jquery-ui/js/jquery.ui.widget.min',
+    'jquery-ui-slider' : '../libs/bower/jquery-ui/js/jquery-ui-slider',
     'globalize': '../libs/bower/globalize/js/globalize',
     'gblMessages' : '../scripts/globalize',
     'bootbox': '../libs/bower/bootbox/js/bootbox',
@@ -137,8 +141,11 @@ require.config({
   enforceDefine: false
 });
 
-require(["App",
+define(["App",
   "router/Router",
+  'jquery-ui',
+  'jquery.ui.widget',
+  'jquery-ui-slider',
   "utils/Overrides",
   "arbor",
   "arbor-tween",

+ 7 - 6
contrib/views/storm/src/main/resources/scripts/router/Router.js

@@ -47,21 +47,22 @@ define([
 		},
 
 		bindRegions: function () {
+			var that = this;
 			require(['modules/Vent'], function(vent){
 				vent.on('Region:showTopologySection', function(){
 					App.rCluster.$el.removeClass('active').hide();
 					App.rTopology.$el.addClass('active').show();
 					if(App.rTopology.$el.children().hasClass('topologyDetailView')){
-						vent.trigger('Breadcrumb:Show');
+						that.topologyDetailAction(App.rTopology.currentView.model.get('id'));
+					} else {
+						that.topologySummaryAction();
 					}
 				});
 
 				vent.on('Region:showClusterSection', function(){
-					if(!App.rCluster.hasView()){
-						require(['views/Cluster/ClusterSummary'], function(ClusterSummaryView){
-							App.rCluster.show(new ClusterSummaryView());
-						});
-					}
+					require(['views/Cluster/ClusterSummary'], function(ClusterSummaryView){
+						App.rCluster.show(new ClusterSummaryView());
+					});
 					App.rTopology.$el.removeClass('active').hide();
 					App.rCluster.$el.addClass('active').show();
 					vent.trigger('Breadcrumb:Hide');

+ 137 - 56
contrib/views/storm/src/main/resources/scripts/utils/Overrides.js

@@ -1,27 +1,28 @@
 /**
-* 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.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 define(['require',
-        'utils/Globals',
-        'utils/Utils',
-        'backgrid',
-        'bootstrap.filestyle',
-        'backbone.forms'], function (require, Globals, Utils) {
+  'utils/Globals',
+  'utils/Utils',
+  'backgrid',
+  'bootstrap.filestyle',
+  'backbone.forms'
+], function(require, Globals, Utils) {
   'use strict';
 
   /**********************************************************************
@@ -32,20 +33,20 @@ define(['require',
    * HtmlCell renders any html code
    * @class Backgrid.HtmlCell
    * @extends Backgrid.Cell
-  */
+   */
   var HtmlCell = Backgrid.HtmlCell = Backgrid.Cell.extend({
 
-     /** @property */
-     className: "html-cell",
-
-     render: function () {
-         this.$el.empty();
-         var rawValue = this.model.get(this.column.get("name"));
-         var formattedValue = this.formatter.fromRaw(rawValue, this.model);
-         this.$el.append(formattedValue);
-         this.delegateEvents();
-         return this;
-     }
+    /** @property */
+    className: "html-cell",
+
+    render: function() {
+      this.$el.empty();
+      var rawValue = this.model.get(this.column.get("name"));
+      var formattedValue = this.formatter.fromRaw(rawValue, this.model);
+      this.$el.append(formattedValue);
+      this.delegateEvents();
+      return this;
+    }
   });
 
   var UriCell = Backgrid.UriCell = Backgrid.Cell.extend({
@@ -53,13 +54,13 @@ define(['require',
     title: null,
     target: "_blank",
 
-    initialize: function (options) {
+    initialize: function(options) {
       UriCell.__super__.initialize.apply(this, arguments);
       this.title = options.title || this.title;
       this.target = options.target || this.target;
     },
 
-    render: function () {
+    render: function() {
       this.$el.empty();
       var rawValue = this.model.get(this.column.get("name"));
       var href = _.isFunction(this.column.get("href")) ? this.column.get('href')(this.model) : this.column.get('href');
@@ -69,13 +70,13 @@ define(['require',
         tabIndex: -1,
         href: href,
         title: this.title || formattedValue,
-        'class' : klass
+        'class': klass
       }).text(formattedValue));
 
-      if(this.column.has("iconKlass")){
+      if (this.column.has("iconKlass")) {
         var iconKlass = this.column.get("iconKlass");
         var iconTitle = this.column.get("iconTitle");
-        this.$el.find('a').append('<i class="'+iconKlass+'" title="'+iconTitle+'"></i>');
+        this.$el.find('a').append('<i class="' + iconKlass + '" title="' + iconTitle + '"></i>');
       }
       this.delegateEvents();
       return this;
@@ -111,34 +112,36 @@ define(['require',
        @param {Backgrid.Column} options.column
        @param {Backbone.Model} options.model
     */
-    initialize: function (options) {
+    initialize: function(options) {
 
       this.column = options.column;
       if (!(this.column instanceof Backgrid.Column)) {
         this.column = new Backgrid.Column(this.column);
       }
 
-      if(!this.column.has("checkedVal")){
+      if (!this.column.has("checkedVal")) {
         this.column.set("checkedVal", "true"); // it is not a boolean value for EPM
         this.column.set("uncheckedVal", "false");
       }
 
-      var column = this.column, model = this.model, $el = this.$el;
-      this.listenTo(column, "change:renderable", function (column, renderable) {
+      var column = this.column,
+        model = this.model,
+        $el = this.$el;
+      this.listenTo(column, "change:renderable", function(column, renderable) {
         $el.toggleClass("renderable", renderable);
       });
 
-      if (Backgrid.callByNeed(column.renderable(), column, model)){
+      if (Backgrid.callByNeed(column.renderable(), column, model)) {
         $el.addClass("renderable");
       }
 
-      this.listenTo(model, "change:" + column.get("name"), function () {
-        if (!$el.hasClass("editor")){
+      this.listenTo(model, "change:" + column.get("name"), function() {
+        if (!$el.hasClass("editor")) {
           this.render();
         }
       });
 
-      this.listenTo(model, "backgrid:select", function (model, selected) {
+      this.listenTo(model, "backgrid:select", function(model, selected) {
         this.$el.find("input[type=checkbox]").prop("checked", selected).change();
       });
 
@@ -148,14 +151,14 @@ define(['require',
     /**
        Focuses the checkbox.
     */
-    enterEditMode: function () {
+    enterEditMode: function() {
       this.$el.find("input[type=checkbox]").focus();
     },
 
     /**
        Unfocuses the checkbox.
     */
-    exitEditMode: function () {
+    exitEditMode: function() {
       this.$el.find("input[type=checkbox]").blur();
     },
 
@@ -164,7 +167,7 @@ define(['require',
        `backgrid:selected` event with a reference of the model and the
        checkbox's `checked` value.
     */
-    onChange: function () {
+    onChange: function() {
       var checked = this.$el.find("input[type=checkbox]").prop("checked");
       this.model.set(this.column.get("name"), checked);
       this.model.trigger("backgrid:selected", this.model, checked);
@@ -173,8 +176,9 @@ define(['require',
     /**
        Renders a checkbox in a table cell.
     */
-    render: function () {
-      var model = this.model, column = this.column;
+    render: function() {
+      var model = this.model,
+        column = this.column;
       var val = (model.get(column.get("name")) === column.get("checkedVal") || model.get(column.get("name")) === true) ? true : false;
       var editable = Backgrid.callByNeed(column.editable(), column, model);
 
@@ -193,16 +197,16 @@ define(['require',
   });
 
   Backbone.Form.editors.Fileupload = Backbone.Form.editors.Base.extend({
-    initialize: function(options){
+    initialize: function(options) {
       Backbone.Form.editors.Base.prototype.initialize.call(this, options);
       this.template = _.template('<input type="file" name="fileInput" class="filestyle">');
     },
-    render: function(){
-      this.$el.html( this.template );
+    render: function() {
+      this.$el.html(this.template);
       this.$(":file").filestyle();
       return this;
     },
-    getValue: function(){
+    getValue: function() {
       return $('input[name="fileInput"]')[0].files[0];
     }
   });
@@ -215,4 +219,81 @@ define(['require',
     return Backbone.$.ajax.apply(Backbone.$, arguments);
   };
 
-});
+  Backbone.Form.editors.RangeSlider = Backbone.Form.editors.Base.extend({
+    ui: {
+
+    },
+    events: {
+      'change #from': 'evChange',
+    },
+
+    initialize: function(options) {
+      this.options = options;
+      Backbone.Form.editors.Base.prototype.initialize.call(this, options);
+      this.template = _.template('<div id="scoreSlider" style="width: 50%; float: left; margin-top: 5px;" class="ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all" aria-disabled="false"><div class="ui-slider-range ui-widget-header ui-corner-all" style="left: 0%; width: 100%; "></div><a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left: 0%; "></a></div><input type="number" id="from" class="input-mini" style="float:left; width: 60px; margin-left: 15px;" placeholder="0"/><div id="sliderLegend" style="width: 50%"><label id="startLabel" style="float: left;">0</label><label id="endLabel" style="float: right;">0</label></div>');
+    },
+
+    evChange: function(e) {
+      var val = e.currentTarget.value;
+      if (val == '') {
+        val = '0';
+      }
+
+      var sanitized = val.replace(/[^0-9]/g, '');
+
+      if (_.isNumber(parseInt(sanitized, 10))) {
+        if (sanitized < this.options.schema.options.max) {
+          $(e.currentTarget).val(sanitized);
+          this.$('#scoreSlider').slider('value', sanitized);
+        } else {
+          $(e.currentTarget).val(this.options.schema.options.max);
+          this.$('#scoreSlider').slider('value', this.options.schema.options.max);
+        }
+      }
+
+    },
+
+    /**
+     * Adds the editor to the DOM
+     */
+    render: function() {
+      this.$el.html(this.template);
+      this.setupSlider(this.options.schema.options);
+      if (this.value)
+        this.setValue(this.value);
+      return this;
+    },
+
+    getValue: function() {
+      return {
+        min: this.$("#from").val(),
+      };
+    },
+
+    setValue: function(value) {
+      this.$("#from").val(value);
+      return this.$('#scoreSlider').slider('value');
+    },
+    setupSlider: function(options) {
+      var that = this;
+      var minVal = options && options.min ? options.min : 0,
+        maxVal = options && options.max ? options.max : 0;
+      this.$('#scoreSlider').slider({
+        range: "max",
+        min: minVal,
+        max: maxVal,
+        value: this.value,
+        slide: function(event, ui) {
+          that.$("#from").val(ui.value);
+        }
+      });
+      this.$('#startLabel').text(minVal);
+      this.$('#endLabel').text(maxVal);
+      this.$('#from').attr("min", minVal);
+      this.$('#from').attr("max", maxVal);
+      if (this.options.schema.minEditorClass)
+        this.$('#from').addClass(this.options.schema.minEditorClass);
+    }
+  });
+
+});

+ 10 - 38
contrib/views/storm/src/main/resources/scripts/views/Cluster/ClusterSummary.js

@@ -73,9 +73,9 @@ define(['require',
       this.fetchData();
 
       this.$('.collapse').on('shown.bs.collapse', function() {
-        $(this).parent().find(".fa-caret-right").removeClass("fa-caret-right").addClass("fa-caret-down");
+        $(this).parent().find(".fa-plus-square").removeClass("fa-plus-square").addClass("fa-minus-square");
       }).on('hidden.bs.collapse', function() {
-        $(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-right");
+        $(this).parent().find(".fa-minus-square").removeClass("fa-minus-square").addClass("fa-plus-square");
       });
 
     },
@@ -91,15 +91,15 @@ define(['require',
       this.clusterCollection.trigger('request', this.clusterCollection);
       model.fetch({
         success: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.clusterCollection.trigger('sync', that.clusterCollection);
           if (model) {
             that.clusterCollection.reset(model);
           }
-          that.startClusterSumPolling();
         },
         error: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.clusterCollection.trigger('error', that.clusterCollection);
-          that.startClusterSumPolling();
           Utils.notifyError(response.statusText);
           return null;
         }
@@ -111,6 +111,7 @@ define(['require',
       this.sprCollection.trigger('request', this.sprCollection);
       model.fetch({
         success: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.sprCollection.trigger('sync', that.sprCollection);
           if (model.has('supervisors') && model.get('supervisors').length) {
             var arr = [];
@@ -119,11 +120,10 @@ define(['require',
             });
             that.sprCollection.reset(arr);
           }
-          that.startSupervisorSumPolling();
         },
         error: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.sprCollection.trigger('error', that.sprCollection);
-          that.startSupervisorSumPolling();
           Utils.notifyError(response.statusText);
         }
       });
@@ -134,6 +134,7 @@ define(['require',
       this.nimbusConfigCollection.trigger('request', this.nimbusConfigCollection);
       model.fetch({
         success: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.nimbusConfigCollection.trigger('sync', that.nimbusConfigCollection);
           if (model) {
             var arr = [];
@@ -145,11 +146,10 @@ define(['require',
             }
             that.nimbusConfigCollection.reset(arr);
           }
-          that.startNimbusConfigPolling();
         },
         error: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.nimbusConfigCollection.trigger('error', that.nimbusConfigCollection);
-          that.startNimbusConfigPolling();
           Utils.notifyError(response.statusText);
         }
       });
@@ -160,6 +160,7 @@ define(['require',
       this.nbsCollection.trigger('request', this.nbsCollection);
       model.fetch({
         success: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.nbsCollection.trigger('sync', that.nbsCollection);
           if (model.has('nimbuses') && model.get('nimbuses').length) {
             var arr = [];
@@ -168,11 +169,10 @@ define(['require',
             });
             that.nbsCollection.reset(arr);
           }
-          that.startNimbusSummaryPolling();
         },
         error: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh');
           that.nbsCollection.trigger('error', that.nbsCollection);
-          that.startNimbusSummaryPolling();
           Utils.notifyError(response.statusText);
         }
       });
@@ -346,34 +346,6 @@ define(['require',
         label: localization.tt("lbl.value")
       }];
       return cols;
-    },
-
-    startClusterSumPolling: function(){
-      var that = this;
-      setTimeout(function(){
-        that.getClusterSummary(that.clusterModel);
-      }, Globals.settings.refreshInterval);
-    },
-
-    startSupervisorSumPolling: function(){
-      var that = this;
-      setTimeout(function(){
-        that.getSupervisorSummary(that.supervisorModel);
-      }, Globals.settings.refreshInterval);
-    },
-
-    startNimbusConfigPolling: function(){
-      var that = this;
-      setTimeout(function(){
-        that.getNimbusConfig(that.nimbusConfigModel);
-      }, Globals.settings.refreshInterval);
-    },
-
-    startNimbusSummaryPolling: function(){
-      var that = this;
-      setTimeout(function(){
-        that.getNimbusSummary(that.nimbusSummaryModel);
-      }, Globals.settings.refreshInterval);
     }
 
   });

+ 54 - 9
contrib/views/storm/src/main/resources/scripts/views/Topology/RebalanceForm.js

@@ -18,44 +18,72 @@
 
 define(['utils/LangSupport',
   'utils/Globals',
+  'hbs!tmpl/topology/rebalanceForm',
+  'models/Cluster',
   'backbone.forms'
-  ], function (localization, Globals) {
+  ], function (localization, Globals, tmpl, clusterModel) {
   'use strict';
 
   var RebalanceForm = Backbone.Form.extend({
 
+    template: tmpl,
+
     initialize: function (options) {
+      this.showSpout = false,
+      this.showBolt = false,
+      this.spoutData = [],
+      this.boltData = [];
       this.spoutCollection = options.spoutCollection;
       this.boltCollection = options.boltCollection;
+      this.model = options.model;
+      this.schemaObj = this.generateSchema();
+      this.templateData = {
+        "spoutFlag": this.showSpout,
+        "boltFlag": this.showBolt,
+        "spoutData": this.spoutData,
+        "boltData": this.boltData,
+        "showParallelism": (this.showSpout && this.showBolt) ? true : false
+      },
       Backbone.Form.prototype.initialize.call(this, options);
     },
 
-    schema: function () {
+    generateSchema: function(){
       var that = this;
+      var freeSlots = this.getClusterSummary(new clusterModel());
+      freeSlots += this.model.get('workers');
       var obj = {
         workers: {
-          type: 'Number',
-          title: localization.tt('lbl.workers')
+          type: 'RangeSlider',
+          title: localization.tt('lbl.workers'),
+          options: {"min":0,"max":freeSlots}
         }
       };
 
       if(that.spoutCollection.length){
         _.each(that.spoutCollection.models, function(model){
           if(model.has('spoutId')) {
-            obj[model.get('spoutId')] = {
+            that.showSpout = true;
+            var name = model.get('spoutId');
+            obj[name] = {
               type: 'Number',
-              title: model.get('spoutId')
+              title: name
             };
+            that.spoutData.push(name);
+            that.model.set(name,model.get('executors'));
           }
         });
       }
       if(that.boltCollection.length){
         _.each(that.boltCollection.models, function(model){
           if(model.has('boltId')) {
-            obj[model.get('boltId')] = {
+            var name = model.get('boltId');
+            that.showBolt = true;
+            obj[name] = {
               type: 'Number',
-              title: model.get('boltId')
+              title: name
             };
+            that.boltData.push(name);
+            that.model.set(name,model.get('executors'));
           }
         });
       }
@@ -64,7 +92,24 @@ define(['utils/LangSupport',
         title: localization.tt('lbl.waitTime')+'*',
         validators: ['required']
       }
-      return obj
+      return obj;
+    },
+
+    getClusterSummary: function(model){
+      var freeSlots = 0;
+      model.fetch({
+        async: false,
+        success: function(model, response, options) {
+          if (model) {
+            freeSlots = model.get('slotsFree');
+          }
+        }
+      });
+      return freeSlots;
+    },
+
+    schema: function () {
+      return this.schemaObj;
     },
 
     render: function(options){

+ 25 - 23
contrib/views/storm/src/main/resources/scripts/views/Topology/TopologyDetail.js

@@ -85,16 +85,16 @@ define(['require',
         sysBoltFlag: flag,
         windowTimeFrame: timeFrame,
         success: function(model, response, options) {
+          vent.trigger('LastUpdateRefresh', true);
           that.model = new vTopology(model);
           that.getDetails(that.model);
           that.render();
           that.disableBtnAction(model.status);
           that.$('#sysBolt').prop("checked",that.systemBoltFlag)
-          that.startPollingAction(that.model.get('id'), that.model.get('window'));
           $('.loading').hide();
         },
         error: function(model, response, options) {
-          that.startPollingAction(that.model.get('id'), that.model.get('window'));
+          vent.trigger('LastUpdateRefresh', true);
           $('.loading').hide();
           Utils.notifyError(model.statusText);
         }
@@ -133,9 +133,12 @@ define(['require',
       }
       this.$('.topology-title').html(this.model.has('name') ? this.model.get('name') : '');
       this.showDetailsTable(this.topologyDetailsColl);
-      if(this.summaryArr.length){
+      if(!_.isUndefined(this.summaryArr) && this.summaryArr.length){
         this.setTimeFrameOptions();
+      } else {
+        $('.loading').hide();
       }
+
       this.windowTimeFrame = this.model.get('window');
       this.$('#tFrame').val(this.windowTimeFrame);
       this.showSummaryTable(this.windowTimeFrame);
@@ -152,9 +155,9 @@ define(['require',
       }
 
       this.$('.collapse').on('shown.bs.collapse', function() {
-        $(this).parent().find(".fa-caret-right").removeClass("fa-caret-right").addClass("fa-caret-down");
+        $(this).parent().find(".fa-plus-square").removeClass("fa-plus-square").addClass("fa-minus-square");
       }).on('hidden.bs.collapse', function() {
-        $(this).parent().find(".fa-caret-down").removeClass("fa-caret-down").addClass("fa-caret-right");
+        $(this).parent().find(".fa-minus-square").removeClass("fa-minus-square").addClass("fa-plus-square");
       });
 
       this.$('[data-id="r_tableList"]').parent().removeClass('col-md-12');
@@ -165,7 +168,7 @@ define(['require',
 
     disableBtnAction: function(status){
       _.each(this.$el.find('.btn.btn-success.btn-sm'),function(elem){
-        $(elem).removeAttr('disabled')
+        $(elem).removeAttr('disabled');
       });
       switch(status){
         case "ACTIVE":
@@ -436,16 +439,20 @@ define(['require',
         this.onDialogClosed();
       }
       require(['views/Topology/RebalanceForm'], function(rebalanceForm){
+        var reBalanceModel = new Backbone.Model();
+        reBalanceModel.set('workers',that.topologyDetailsColl.models[0].get('workersTotal'));
+        reBalanceModel.set('waitTime',30);
         that.view = new rebalanceForm({
           spoutCollection : that.spoutsCollection,
-          boltCollection: that.boltsCollection
+          boltCollection: that.boltsCollection,
+          model: reBalanceModel
         });
         that.view.render();
 
         bootbox.dialog({
           message: that.view.$el,
           title: localization.tt('lbl.rebalanceTopology'),
-          className: "topology-modal",
+          className: "rebalance-modal",
           buttons: {
             cancel: {
               label: localization.tt('btn.cancel'),
@@ -455,7 +462,7 @@ define(['require',
               }
             },
             success: {
-              label: localization.tt('btn.save'),
+              label: localization.tt('btn.apply'),
               className: "btn-success",
               callback: function(){
                 var err = that.view.validate();
@@ -473,8 +480,8 @@ define(['require',
           attr = this.view.getValue(),
           obj = {"rebalanceOptions":{}};
 
-      if(!_.isUndefined(attr.workers) && !_.isNull(attr.workers)){
-        obj.rebalanceOptions.numWorkers = attr.workers;
+      if(!_.isUndefined(attr.workers.min) && !_.isNull(attr.workers.min)){
+        obj.rebalanceOptions.numWorkers = attr.workers.min;
       }
 
       var spoutBoltObj = {};
@@ -498,7 +505,13 @@ define(['require',
         type: 'POST',
         success: function(model, response, options){
           if(!_.isUndefined(model.error)){
-            Utils.notifyError(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(localization.tt('dialogMsg.topologyRebalanceSuccessfully'));
             that.fetchData(that.model.get('id'), that.systemBoltFlag, that.windowTimeFrame);
@@ -703,9 +716,7 @@ define(['require',
     },
 
     getTopoConfigColumns: function() {
-
       var cols = [
-
         {
           name: "key",
           cell: "string",
@@ -718,15 +729,6 @@ define(['require',
         }
       ];
       return cols;
-    },
-
-    startPollingAction: function(id){
-      var that = this;
-      setTimeout(function(){
-        if(_.isEqual(typeof that.ui.BoltsSummaryDetails, "object")){
-          that.fetchData(id, that.systemBoltFlag, that.windowTimeFrame);
-        }
-      }, Globals.settings.refreshInterval);
     }
 
   });

+ 20 - 19
contrib/views/storm/src/main/resources/scripts/views/Topology/TopologySummary.js

@@ -37,7 +37,7 @@ define(['require',
     templateHelpers: function() {},
 
     events: {
-      'click [data-id="deployBtn"]': 'evDeployTopology'
+      // 'click [data-id="deployBtn"]': 'evDeployTopology'
     },
 
     ui: {
@@ -53,23 +53,31 @@ define(['require',
       vent.trigger('Breadcrumb:Hide');
     },
 
-    fetchSummary: function(flag) {
+    fetchSummary: function(topologyName) {
       var that = this;
       this.collection.fetch({
         success: function(collection, response, options) {
+          vent.trigger('LastUpdateRefresh');
           if (collection && collection.length) {
             var arr = [];
             _.each(collection.models[0].get('topologies'), function(object){
-              arr.push(new mTopology(object));
+              if(!_.isUndefined(topologyName) && object.name === topologyName){
+                Backbone.history.navigate('!/topology/'+object.id, {trigger:true});
+              } else {
+                arr.push(new mTopology(object));
+              }
             });
-            that.countActive = 0;
-            that.collection.reset(arr);
-            that.showSummaryDetail();
-            that.startPollingAction();
+            if(_.isUndefined(topologyName)){
+              that.countActive = 0;
+              that.collection.reset(arr);
+              that.showSummaryDetail();
+            } else {
+              $('.loading').hide();
+            }
           }
         },
         error: function(collection, response, options){
-          that.startPollingAction();
+          vent.trigger('LastUpdateRefresh');
           Utils.notifyError(response.statusText);
         }
       })
@@ -263,18 +271,21 @@ define(['require',
           response = JSON.parse(response);
         }
         if(_.isEqual(response.status, 'failed')){
+          $('.loading').hide();
           Utils.notifyError(response.error);
         } else {
           Utils.notifySuccess(localization.tt("dialogMsg.topologyDeployedSuccessfully"));
-          that.fetchSummary(true);
+          that.fetchSummary(attrs.name);
         }
       };
 
       var errorCallback = function(){
+        $('.loading').hide();
         Utils.notifyError(localization.tt("dialogMsg.topologyDeployFailed"));
       };
 
       Utils.uploadFile(url,formData,successCallback, errorCallback);
+      $('.loading').show();
     },
 
     onDialogClosed: function() {
@@ -283,16 +294,6 @@ define(['require',
         this.view.remove();
         this.view = null;
       }
-    },
-
-    startPollingAction: function(){
-      var that = this;
-      setTimeout(function() {
-        if(_.isEqual(typeof that.ui.summaryDetails, "object")){
-          that.fetchSummary();
-        }
-      }, Globals.settings.refreshInterval);
-
     }
 
   });

+ 27 - 7
contrib/views/storm/src/main/resources/scripts/views/site/Header.js

@@ -40,7 +40,8 @@ define(['require',
 
     events: {
       'click [data-id="topology"]': 'showTopologySection',
-      'click [data-id="cluster"]': 'showClusterSection'
+      'click [data-id="cluster"]': 'showClusterSection',
+      'click #refresh' : 'evRefresh'
     },
 
     initialize: function (options) {
@@ -57,20 +58,39 @@ define(['require',
       vent.on('Breadcrumb:Hide', function(){
         that.$('.breadcrumb').addClass('displayNone');
       });
+      vent.on('LastUpdateRefresh', function(flag){
+        if(flag)
+          that.$('.last-refreshed').css("margin-top","0px");
+        else
+          that.$('.last-refreshed').css("margin-top","35px");
+        that.$('#refreshTime').html(new Date().toLocaleString());
+      });
     },
 
     onRender: function () {},
 
     showTopologySection: function () {
-      this.ui.clusterLink.parent().removeClass('active');
-      this.ui.toplogyLink.parent().addClass('active');
-      vent.trigger('Region:showTopologySection');
+      if(!this.ui.toplogyLink.parent().hasClass('active')){
+        this.ui.clusterLink.parent().removeClass('active');
+        this.ui.toplogyLink.parent().addClass('active');
+        vent.trigger('Region:showTopologySection');
+      }
     },
 
     showClusterSection: function () {
-      this.ui.toplogyLink.parent().removeClass('active');
-      this.ui.clusterLink.parent().addClass('active');
-      vent.trigger('Region:showClusterSection');
+      if(!this.ui.clusterLink.parent().hasClass('active')){
+        this.ui.toplogyLink.parent().removeClass('active');
+        this.ui.clusterLink.parent().addClass('active');
+        vent.trigger('Region:showClusterSection');
+      }
+    },
+
+    evRefresh: function(){
+      if(this.ui.toplogyLink.parent().hasClass('active')){
+        vent.trigger('Region:showTopologySection');
+      } else {
+        vent.trigger('Region:showClusterSection');
+      }
     }
 
   });

+ 34 - 18
contrib/views/storm/src/main/resources/styles/default.css

@@ -1,20 +1,6 @@
 /**
-* 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.
-*/
+ * CSS Goes here
+ */
 
 /* Generic */
 /*body {
@@ -30,6 +16,16 @@ a:hover, a:focus {
   text-decoration: none;
 }
 
+fieldset {
+  border: 1px solid #CCC;
+  margin-bottom: 20px;
+}
+
+legend {
+  font-size: 13px;
+  padding: 0 7px;
+}
+
 [data-error]{
   color: red;
 }
@@ -72,6 +68,11 @@ a:hover, a:focus {
   border-left: 4px solid transparent;
 }
 
+.rebalance-modal .modal-body {
+  height: 470px;
+  overflow: auto;
+}
+
 /*.tab-content>.tab-pane {
   padding: 0 20px;
 }*/
@@ -117,7 +118,7 @@ a:hover, a:focus {
   background: green 50% 50% repeat-x;
 }
 
-.topology-modal .modal-header {
+.modal-header {
   color:#53c749;
 }
 
@@ -286,7 +287,7 @@ border-bottom: 0;
 }
 
 .breadcrumb {
-  line-height: 52px;
+  line-height: 35px;
   margin-left: 25px;
   font-size: 12px;
   color: #666;
@@ -309,4 +310,19 @@ th.sortable > div > a {
 table tr.recent > td {
   background-color: #3FC846;
   color: #fff;
+}
+.last-refreshed {
+  float: right;
+  font-size: 12px;
+  margin-right: 5px;
+  margin-top: 35px;
+  color: #8B8787;
+}
+.refresh-icon {
+  padding-left: 10px;
+  font-size: 1.5em;
+  margin-left: 7px;
+  color: #5cb85c;
+  border-left: 1px #BBB solid;
+  cursor: pointer;
 }

+ 4 - 4
contrib/views/storm/src/main/resources/templates/cluster/clusterSummary.html

@@ -31,7 +31,7 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
                 <div class="panel-heading" role="tab" id="headingOne">
                     <h6 class="panel-title">
                         <a data-toggle="collapse" href="#collapseNimbSum" aria-expanded="true" aria-controls="collapseNimbSum" class="">
-                        <i class="fa fa-caret-down"></i> {{tt "h.nimbusSummary"}}</a>
+                        <i class="fa fa-minus-square"></i> {{tt "h.nimbusSummary"}}</a>
                     </h6>
                 </div>
                 <div id="collapseNimbSum" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne" aria-expanded="true">
@@ -51,7 +51,7 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
                 <div class="panel-heading" role="tab" id="headingTwo">
                     <h6 class="panel-title">
                         <a data-toggle="collapse" href="#collapseSubSum" aria-expanded="true" aria-controls="collapseSubSum">
-                        <i class="fa fa-caret-down"></i> {{tt "h.supervisorSummary"}}</a>
+                        <i class="fa fa-minus-square"></i> {{tt "h.supervisorSummary"}}</a>
                     </h6>
                 </div>
                 <div id="collapseSubSum" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
@@ -71,10 +71,10 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
                 <div class="panel-heading" role="tab" id="headingThree">
                     <h6 class="panel-title">
                         <a data-toggle="collapse" href="#collapseNbs" aria-expanded="true" aria-controls="collapseNbs">
-                        <i class="fa fa-caret-down"></i> {{tt "h.nimbusConfiguration"}}</a>
+                        <i class="fa fa-plus-square"></i> {{tt "h.nimbusConfiguration"}}</a>
                     </h6>
                 </div>
-                <div id="collapseNbs" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
+                <div id="collapseNbs" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
                     <div class="panel-body"> <div class="row" id="nbsConfigTable"> </div> </div>
                 </div>
             </div>

+ 6 - 0
contrib/views/storm/src/main/resources/templates/site/header.html

@@ -19,5 +19,11 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
     <li role="presentation" class="active"><a role="tab" data-toggle="tab" data-id="topology">{{tt 'h.topologies'}}</a></li>
     <li role="presentation"><a role="tab" data-toggle="tab" data-id="cluster">{{tt 'h.cluster'}}</a></li>
     <span class="breadcrumb displayNone"><a href="#!/topology">{{tt 'h.topologies'}}</a> <i class="fa fa-angle-double-right seperator"></i><span id="breadcrumbName"></span></span>
+    <span class="last-refreshed">Last refreshed @
+      <span id="refreshTime"></span>
+      <span class="refresh-icon" id="refresh" data-toggle="tooltip" title="Refresh Now">
+        <i class="fa fa-refresh"></i>
+      </span>
+    </span>
   </ul>
 </div>

+ 26 - 0
contrib/views/storm/src/main/resources/templates/topology/rebalanceForm.html

@@ -0,0 +1,26 @@
+<form class="form-horizontal">
+  <fieldset>
+    <legend>Worker</legend>
+    <div class="" data-fields="workers"></div>
+  </fieldset>
+  {{#if showParallelism}}
+  <fieldset>
+      <legend>Parallelism</legend>
+    {{#if spoutFlag}}
+      {{#each spoutData}}
+        <div class="" data-fields="{{this}}"></div>
+      {{/each}}
+
+    {{/if}}
+    {{#if boltFlag}}
+      {{#each boltData}}
+        <div class="" data-fields="{{this}}"></div>
+      {{/each}}
+    {{/if}}
+  </fieldset>
+  {{/if}}
+  <fieldset>
+    <legend>Wait Time</legend>
+    <div class="" data-fields="waitTime"></div>
+  </fieldset>
+</form>

+ 6 - 6
contrib/views/storm/src/main/resources/templates/topology/topologyDetail.html

@@ -60,10 +60,10 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
         <div class="panel-heading" role="tab">
           <h6 class="panel-title">
             <a class="collapsed" data-toggle="collapse" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
-            <i class="fa fa-caret-down"></i> {{tt 'lbl.spouts'}}</a>
+            <i class="fa fa-plus-square"></i> {{tt 'lbl.spouts'}}</a>
           </h6>
         </div>
-        <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
+        <div id="collapseOne" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
           <div class="panel-body" id="SpoutsTable"></div>
         </div>
       </div>
@@ -73,10 +73,10 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
       <div class="panel panel-default">
         <div class="panel-heading" role="tab" id="headingTwo">
           <h6 class="panel-title">
-            <a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"><span class="fa fa-caret-down"></span> {{tt 'lbl.bolts'}}</a>
+            <a class="collapsed" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"><span class="fa fa-plus-square"></span> {{tt 'lbl.bolts'}}</a>
           </h6>
         </div>
-        <div id="collapseTwo" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingTwo">
+        <div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">
           <div class="panel-body">
             <div class="row statistics-row">
               <div id="BoltsSummaryTable"></div>
@@ -90,10 +90,10 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
       <div class="panel panel-default">
         <div class="panel-heading" role="tab" id="headingThree">
           <h6 class="panel-title">
-            <a class="collapsed" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree"><span class="fa fa-caret-down"></span> {{tt 'lbl.topologyConfig'}}</a>
+            <a class="collapsed" data-toggle="collapse" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree"><span class="fa fa-plus-square"></span> {{tt 'lbl.topologyConfig'}}</a>
           </h6>
         </div>
-        <div id="collapseThree" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingThree">
+        <div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
           <div class="panel-body">
             <div class="row statistics-row">
               <div id="TopologyConfigTable"></div>

+ 4 - 22
contrib/views/storm/src/main/resources/templates/topology/topologyForm.html

@@ -1,24 +1,6 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements. See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License. You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
--->
 <form class="form-horizontal">
-  <fieldset>
-    <div class="" data-fields="name"></div>
-    <div class="" data-fields="jar"></div>
-    <div class="" data-fields="topologyClass"></div>
-    <div class="" data-fields="arguments"></div>
-  </fieldset>
+  <div class="" data-fields="name"></div>
+  <div class="" data-fields="jar"></div>
+  <div class="" data-fields="topologyClass"></div>
+  <div class="" data-fields="arguments"></div>
 </form>

+ 2 - 2
contrib/views/storm/src/main/resources/templates/topology/topologySummary.html

@@ -16,8 +16,8 @@ limitations under the License. Kerberos, LDAP, Custom. Binary/Htt
 -->
 <div class="row row-margin-bottom">
   <div class="col-md-6" data-id="summary"></div>
-  <div class="col-md-6">
+  <!-- <div class="col-md-6">
     <button class="btn btn-success btn-sm pull-right" data-id="deployBtn"> {{tt 'btn.deployNewTopology'}}  </button>
-  </div>
+  </div> -->
 </div>
 <div class="row" id="summaryTable"></div>

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff