eagle-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ji...@apache.org
Subject incubator-eagle git commit: EAGLE-193 UI metric dashboard support sortable For metrics -> Dashboard, support sort-able to easily adjust charts position.
Date Thu, 10 Mar 2016 03:34:41 GMT
Repository: incubator-eagle
Updated Branches:
  refs/heads/master cab2e42d0 -> 625f7c19a


EAGLE-193 UI metric dashboard support sortable
For metrics -> Dashboard, support sort-able to easily adjust charts position.

https://issues.apache.org/jira/browse/EAGLE-193

Author: @zombiej
Reviewer: @qingwen220

Closes #119


Project: http://git-wip-us.apache.org/repos/asf/incubator-eagle/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-eagle/commit/625f7c19
Tree: http://git-wip-us.apache.org/repos/asf/incubator-eagle/tree/625f7c19
Diff: http://git-wip-us.apache.org/repos/asf/incubator-eagle/diff/625f7c19

Branch: refs/heads/master
Commit: 625f7c19a8827c1cae762b0d4ab7e0e5a9b23d4f
Parents: cab2e42
Author: jiljiang <jiljiang@ebay.com>
Authored: Thu Mar 10 11:30:37 2016 +0800
Committer: jiljiang <jiljiang@ebay.com>
Committed: Thu Mar 10 11:34:21 2016 +0800

----------------------------------------------------------------------
 eagle-webservice/src/main/webapp/app/index.html |   1 +
 .../src/main/webapp/app/public/css/main.css     |  56 ++++++-
 .../app/public/feature/metrics/controller.js    |  45 +++++-
 .../public/feature/metrics/page/dashboard.html  |  23 ++-
 .../src/main/webapp/app/public/js/app.js        |   5 +-
 .../src/main/webapp/app/public/js/common.js     |  11 +-
 .../webapp/app/public/js/components/sortable.js | 152 +++++++++++++++++++
 7 files changed, 272 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/index.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/index.html b/eagle-webservice/src/main/webapp/app/index.html
index cd58877..3311d8c 100644
--- a/eagle-webservice/src/main/webapp/app/index.html
+++ b/eagle-webservice/src/main/webapp/app/index.html
@@ -235,6 +235,7 @@
 		<script src="public/js/components/file.js" type="text/javascript" charset="utf-8"></script>
 		<script src="public/js/components/charts/line3d.js" type="text/javascript" charset="utf-8"></script>
 		<script src="public/js/components/nvd3.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/components/sortable.js" type="text/javascript" charset="utf-8"></script>
 
 		<!-- Controllers -->
 		<script src="public/js/ctrl/main.js" type="text/javascript" charset="utf-8"></script>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/css/main.css
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/css/main.css b/eagle-webservice/src/main/webapp/app/public/css/main.css
index b32c4fe..b6e848e 100644
--- a/eagle-webservice/src/main/webapp/app/public/css/main.css
+++ b/eagle-webservice/src/main/webapp/app/public/css/main.css
@@ -446,10 +446,40 @@ ul.tree.tree-bordered > li > ul > li > a {
 	color: #FFFFFF;
 }
 
+/* Row */
+.row.narrow {
+	margin-left: -5px;
+	margin-right: -5px;
+	margin-bottom: -10px;
+}
+
+.row.narrow>.col-xs-1, .row.narrow>.col-sm-1, .row.narrow>.col-md-1, .row.narrow>.col-lg-1,
.row.narrow>.col-xs-2, .row.narrow>.col-sm-2, .row.narrow>.col-md-2, .row.narrow>.col-lg-2,
.row.narrow>.col-xs-3, .row.narrow>.col-sm-3, .row.narrow>.col-md-3, .row.narrow>.col-lg-3,
.row.narrow>.col-xs-4, .row.narrow>.col-sm-4, .row.narrow>.col-md-4, .row.narrow>.col-lg-4,
.row.narrow>.col-xs-5, .row.narrow>.col-sm-5, .row.narrow>.col-md-5, .row.narrow>.col-lg-5,
.row.narrow>.col-xs-6, .row.narrow>.col-sm-6, .row.narrow>.col-md-6, .row.narrow>.col-lg-6,
.row.narrow>.col-xs-7, .row.narrow>.col-sm-7, .row.narrow>.col-md-7, .row.narrow>.col-lg-7,
.row.narrow>.col-xs-8, .row.narrow>.col-sm-8, .row.narrow>.col-md-8, .row.narrow>.col-lg-8,
.row.narrow>.col-xs-9, .row.narrow>.col-sm-9, .row.narrow>.col-md-9, .row.narrow>.col-lg-9,
.row.narrow>.col-xs-10, .row.narrow>.col-sm-10, .row.narrow>.col-md-10, .row.narrow>.col-lg-10,
.row.narrow>.col-xs-11, .row.narrow>.col-sm-11, .row.narrow>.col-md-11, .
 row.narrow>.col-lg-11, .row.narrow>.col-xs-12, .row.narrow>.col-sm-12, .row.narrow>.col-md-12,
.row.narrow>.col-lg-12 {
+	padding-left: 5px;
+	padding-right: 5px;
+}
+
+.row.narrow > [class^="col-"],
+.row.narrow > [class*=" col-"] {
+	margin-bottom: 10px;
+}
+
 /* Chart */
+.sortable-mock-element .nvd3-chart-wrapper {
+	background: #FFFFFF;
+	opacity: 0.8;
+}
+
+.sortable-enter .nvd3-chart-wrapper {
+	border-color: #3c8dbc;
+	pointer-events: none;
+}
+.sortable-enter .nvd3-chart-wrapper .nvtooltip {
+	display: none;
+}
+
 .nvd3-chart-wrapper {
 	position: relative;
-	//border: 1px solid rgba(0,0,0,0);
+	border: 1px solid rgba(0,0,0,0.1);
 }
 .nvd3-chart-wrapper:hover {
 	//border-color: #F4F4F4;
@@ -457,10 +487,10 @@ ul.tree.tree-bordered > li > ul > li > a {
 
 .nvd3-chart-wrapper .nvd3-chart-config {
 	position: absolute;
-	top: 5px;
-	right: 10px;
+	top: 1px;
+	right: 1px;
 	display: none;
-	border-radius: 3px;
+	border-radius: 0;
 	padding: 0 5px;
 	background: rgba(0,0,0,0.7);
 }
@@ -470,7 +500,7 @@ ul.tree.tree-bordered > li > ul > li > a {
 
 .nvd3-chart-wrapper .nvd3-chart-config a {
 	color: rgba(255,255,255, 0.9);
-	padding: 5px 5px 4px 5px;
+	padding: 5px 2px 4px 2px;
 	font-size: 16px;
 }
 .nvd3-chart-wrapper .nvd3-chart-config a:hover {
@@ -478,7 +508,7 @@ ul.tree.tree-bordered > li > ul > li > a {
 }
 
 .nvd3-chart-cntr {
-	padding-top: 10px;
+	padding: 5px;
 }
 
 .nvd3-chart-cntr > h3 {
@@ -486,6 +516,11 @@ ul.tree.tree-bordered > li > ul > li > a {
 	font-size: 16px;
 	font-weight: bolder;
 	margin: 0;
+	padding: 5px 0;
+
+	overflow:hidden;
+	text-overflow:ellipsis;
+
 }
 
 .nvd3-chart-cntr > svg.nvd3-svg {
@@ -677,6 +712,13 @@ td.text-ellipsis {
 	padding: 2px 6px;
 }
 
+.form-control.input-xs {
+	height: 24px;
+	padding: 2px 8px;
+	font-size: 12px;
+	line-height: 100%;
+}
+
 .noSelect {
 	-khtml-user-select: none;
 	-moz-user-select: none;
@@ -684,4 +726,4 @@ td.text-ellipsis {
 	user-select: none;
 	-webkit-touch-callout: none;
 	-webkit-user-select: none;
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/feature/metrics/controller.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/feature/metrics/controller.js b/eagle-webservice/src/main/webapp/app/public/feature/metrics/controller.js
index 27faf07..95e6638 100644
--- a/eagle-webservice/src/main/webapp/app/public/feature/metrics/controller.js
+++ b/eagle-webservice/src/main/webapp/app/public/feature/metrics/controller.js
@@ -288,7 +288,6 @@
 
 		$scope.configPreviewChartMinimumCheck = function() {
 			$scope.configPreviewChart.min = $scope.configPreviewChart.min === 0 ? undefined : 0;
-			window.ccc1 = $scope.getChartConfig($scope.configPreviewChart);
 		};
 
 		$scope.seriesChecked = function(chart, series) {
@@ -322,7 +321,7 @@
 
 		$scope.configChart = function(chart) {
 			$scope.configTargetChart = chart;
-			$scope.configPreviewChart = $.extend({}, chart);
+			$scope.configPreviewChart = $.extend({}, chart, {aggregations: (chart.aggregations ||
[]).slice()});
 			delete $scope.configPreviewChart._config;
 			$("#chartMDL").modal();
 			setTimeout(function() {
@@ -341,11 +340,11 @@
 			UI.deleteConfirm(chart.metric).then(null, null, function(holder) {
 				common.array.remove(chart, group.charts);
 				holder.closeFunc();
-				$scope.chartRefresh();
+				$scope.chartRefresh(false, true);
 			});
 		};
 
-		$scope.chartRefresh = function(forceRefresh) {
+		$scope.chartRefresh = function(forceRefresh, refreshAll) {
 			setTimeout(function() {
 				$scope.endTime = app.time.now();
 				$scope.startTime = $scope.autoRefreshSelect.getStartTime($scope.endTime);
@@ -380,21 +379,55 @@
 							$http.post(_druidConfig.broker + "/druid/v2", _data, {withCredentials: false}).then(function
(response) {
 								chart._oriData = nvd3.convert.druid([response.data]);
 								$scope.chartSeriesUpdate(chart);
-								if(chart._holder) chart._holder.refresh();
+								if(chart._holder) {
+									if(refreshAll) {
+										chart._holder.refreshAll();
+									} else {
+										chart._holder.refresh();
+									}
+								}
 							});
 						} else {
-							if(chart._holder) chart._holder.refresh();
+							if(chart._holder) {
+								if(refreshAll) {
+									chart._holder.refreshAll();
+								} else {
+									chart._holder.refresh();
+								}
+							}
 						}
 					});
 				});
+
+				$(window).resize();
 			}, 0);
 		};
 
+		$scope.chartSwitchRefresh = function(source, target) {
+			var _oriSize = source.size;
+			source.size = target.size;
+			target.size = _oriSize;
+
+			if(source._holder) source._holder.refreshAll();
+			if(target._holder) target._holder.refreshAll();
+
+		};
+
 		_refreshInterval = setInterval(function() {
 			if(!$scope.dashboardReady) return;
 			$scope.chartRefresh(true);
 		}, 1000 * 30);
 
+		// > Chart UI
+		$scope.configChartSize = function(chart, sizeOffset) {
+			chart.size = (chart.size || 6) + sizeOffset;
+			if(chart.size <= 0) chart.size = 1;
+			if(chart.size > 12) chart.size = 12;
+			setTimeout(function() {
+				$(window).resize();
+			}, 1);
+		};
+
 		// ====================== Clean Up ======================
 		$scope.$on('$destroy', function() {
 			clearInterval(_refreshInterval);

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/feature/metrics/page/dashboard.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/feature/metrics/page/dashboard.html
b/eagle-webservice/src/main/webapp/app/public/feature/metrics/page/dashboard.html
index df85c10..48fe738 100644
--- a/eagle-webservice/src/main/webapp/app/public/feature/metrics/page/dashboard.html
+++ b/eagle-webservice/src/main/webapp/app/public/feature/metrics/page/dashboard.html
@@ -57,12 +57,14 @@
 
 <div tabs menu="menu" holder="tabHolder" ng-show="dashboard.groups.length">
 	<pane ng-repeat="group in dashboard.groups" data-data="group" data-title="{{group.name}}">
-		<div class="row">
-			<div ng-repeat="chart in group.charts track by $index" class="col-md-6">
+		<div sortable class="row narrow" ng-model="group.charts" update-func="chartSwitchRefresh"
ng-show="group.charts.length">
+			<div ng-repeat="chart in group.charts track by $index" class="col-md-{{chart.size ||
6}}">
 				<div class="nvd3-chart-wrapper">
-					<div nvd3="chart._data" data-holder="chart._holder" data-title="{{chart.metric}}"
data-watching="false"
+					<div nvd3="chart._data" data-holder="chart._holder" data-title="{{chart.title ||
chart.metric}}" data-watching="false"
 						 data-chart="{{chart.chart || 'line'}}" data-config="getChartConfig(chart)" class="nvd3-chart-cntr"></div>
 					<div class="nvd3-chart-config" ng-if="Auth.isRole('ROLE_ADMIN')">
+						<a class="fa fa-minus" ng-click="configChartSize(chart, -1)"></a>
+						<a class="fa fa-plus" ng-click="configChartSize(chart, 1)"></a>
 						<a class="fa fa-cog" ng-click="configChart(chart)"></a>
 						<a class="fa fa-trash" ng-click="deleteChart(group, chart)"></a>
 					</div>
@@ -72,7 +74,12 @@
 
 		<p ng-if="!group.charts.length">
 			Empty group.
-			<span ng-if="Auth.isRole('ROLE_ADMIN')">Click <a ng-click="newChart()">here</a>
to add metric.</span>
+			<span ng-if="Auth.isRole('ROLE_ADMIN')">
+				Click
+				<span ng-hide="dataSourceListReady" class="fa fa-refresh fa-spin"></span>
+				<a ng-show="dataSourceListReady" ng-click="newChart()">here</a>
+				to add metric.
+			</span>
 		</p>
 	</pane>
 </div>
@@ -145,7 +152,7 @@
 				<div class="row">
 					<div class="col-md-6">
 						<div class="nvd3-chart-wrapper">
-							<div nvd3="configPreviewChart._data" data-title="{{configPreviewChart.metric}}"
data-holder="configPreviewChart._holder"
+							<div nvd3="configPreviewChart._data" data-title="{{configPreviewChart.title ||
configPreviewChart.metric}}"
 								 data-watching="true" data-chart="{{configPreviewChart.chart || 'line'}}" data-config="getChartConfig(configPreviewChart)"
class="nvd3-chart-cntr"></div>
 						</div>
 					</div>
@@ -154,7 +161,11 @@
 						<table class="table">
 							<tbody>
 							<tr>
-								<th width="100">Chart Type</th>
+								<th width="100">Name</th>
+								<td><input type="text" class="form-control input-xs" ng-model="configPreviewChart.title"
placeholder="Default: {{configPreviewChart.metric}}" /></td>
+							</tr>
+							<tr>
+								<th>Chart Type</th>
 								<td>
 									<div class="btn-group" data-toggle="buttons">
 										<label class="btn btn-default btn-xs" ng-class="{active: (configPreviewChart.chart
|| 'line') === type.chart}"

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/js/app.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/app.js b/eagle-webservice/src/main/webapp/app/public/js/app.js
index dc3f538..80b6aa0 100644
--- a/eagle-webservice/src/main/webapp/app/public/js/app.js
+++ b/eagle-webservice/src/main/webapp/app/public/js/app.js
@@ -226,7 +226,7 @@ var app = {};
 	// ======================================================================================
 	// =                                   Router config                                   
=
 	// ======================================================================================
-	eagleApp.config(function ($stateProvider, $urlRouterProvider) {
+	eagleApp.config(function ($stateProvider, $urlRouterProvider, $animateProvider) {
 		// Resolve
 		function _resolve(config) {
 			config = config || {};
@@ -367,6 +367,9 @@ var app = {};
 			.state('page', $.extend({url: "/:feature/:page"}, _featureBase))
 			.state('pageFilter', $.extend({url: "/:feature/:page/:filter"}, _featureBase))
 		;
+
+		// Animation
+		$animateProvider.classNameFilter(/^((?!(fa-spin)).)*$/);
 	});
 
 	eagleApp.filter('parseJSON', function () {

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/js/common.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/common.js b/eagle-webservice/src/main/webapp/app/public/js/common.js
index 92c4f86..0e238b8 100644
--- a/eagle-webservice/src/main/webapp/app/public/js/common.js
+++ b/eagle-webservice/src/main/webapp/app/public/js/common.js
@@ -247,4 +247,13 @@ common.map.toArray = function(map) {
 	return $.map(map, function(unit) {
 		return unit;
 	});
-};
\ No newline at end of file
+};
+
+// ======================= Math =======================
+common.math = {};
+
+common.math.distance = function(x1,y1,x2,y2) {
+	var a = x1 - x2;
+	var b = y1 - y2;
+	return Math.sqrt(a * a + b * b);
+};

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/625f7c19/eagle-webservice/src/main/webapp/app/public/js/components/sortable.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/components/sortable.js b/eagle-webservice/src/main/webapp/app/public/js/components/sortable.js
new file mode 100644
index 0000000..be2fb16
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/app/public/js/components/sortable.js
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+eagleComponents.directive('sortable', function($rootScope) {
+	'use strict';
+
+	var _move = false;
+	var _selectElement;
+	var _overElement;
+	var _mockElement;
+	var _offsetX, _offsetY;
+	var _mouseDownPageX, _mouseDownPageY;
+
+	function doMock(element, event) {
+		var _offset = element.offset();
+		if(_mockElement) _mockElement.remove();
+
+		// Create mock element
+		_mockElement = element.clone(false).appendTo("body");
+		_mockElement.addClass("sortable-mock-element");
+		_mockElement.css({
+			display: "block",
+			position: "absolute",
+			"pointer-events": "none",
+			"z-index": 10001,
+			padding: element.css("padding"),
+			margin: element.css("margin")
+		});
+		_mockElement.width(element.width());
+		_mockElement.height(element.height());
+
+		_mockElement.offset(_offset);
+		_offsetX = event.pageX - _offset.left;
+		_offsetY = event.pageY - _offset.top;
+	}
+
+	$(window).on("mousemove", function(event) {
+		if(!_move) return;
+		event.preventDefault();
+
+		_mockElement.offset({
+			left: event.pageX - _offsetX,
+			top: event.pageY - _offsetY
+		});
+	});
+
+	$(window).on("mouseup", function() {
+		if(!_move) {
+			_overElement = null;
+			_selectElement = null;
+			_mockElement = null;
+			return;
+		}
+		_move = false;
+
+		if(_overElement) {
+			_overElement.removeClass("sortable-enter");
+
+			if(_overElement[0] !== _selectElement[0]) {
+				// Process switch
+				var _oriIndex = angular.element(_selectElement).scope().$index;
+				var _tgtIndex = angular.element(_overElement).scope().$index;
+				var _oriHolder = _selectElement.holder;
+				var _tgtHolder = _overElement.holder;
+				var _oriScope = _oriHolder.scope;
+				var _tgtScope = _tgtHolder.scope;
+
+				var _oriUnit = _oriScope.ngModel[_oriIndex];
+				var _tgtUnit = _tgtScope.ngModel[_tgtIndex];
+				_oriScope.ngModel[_oriIndex] = _tgtUnit;
+				_tgtScope.ngModel[_tgtIndex] = _oriUnit;
+
+				// Trigger event
+				_oriHolder.change(_oriUnit, _tgtUnit);
+				if (_oriHolder !== _tgtHolder) _tgtHolder.change(_oriUnit, _tgtUnit);
+
+				$rootScope.$apply();
+			}
+		}
+
+		if(_mockElement) _mockElement.remove();
+
+		_overElement = null;
+		_selectElement = null;
+		_mockElement = null;
+	});
+
+	return {
+		require: 'ngModel',
+		restrict : 'AE',
+		scope: {
+			ngModel: "=",
+			updateFunc: "=?updateFunc"
+		},
+		link: function($scope, $element, $attrs, $ctrl) {
+			var _holder = {
+				scope: $scope,
+				change: function(source, target) {
+					if($scope.updateFunc) $scope.updateFunc(source, target);
+				}
+			};
+
+			$element.on("mousedown", ">", function(event) {
+				_selectElement = $(this);
+				_selectElement.holder = _holder;
+
+				_mouseDownPageX = event.pageX;
+				_mouseDownPageY = event.pageY;
+
+				event.preventDefault();
+			});
+
+			$element.on("mousemove", ">", function(event) {
+				if(_selectElement && !_move && common.math.distance(_mouseDownPageX,
_mouseDownPageY, event.pageX, event.pageY) > 10) {
+					_move = true;
+					_overElement = _selectElement;
+					_overElement.addClass("sortable-enter");
+
+					doMock(_selectElement, event);
+				}
+			});
+
+			$element.on("mouseenter", ">", function() {
+				if(!_move) return;
+				_overElement = $(this);
+				_overElement.holder = _holder;
+				_overElement.addClass("sortable-enter");
+			});
+			$element.on("mouseleave", ">", function() {
+				if(!_move) return;
+				$(this).removeClass("sortable-enter");
+				_overElement = null;
+			});
+		},
+		replace: false
+	};
+});
\ No newline at end of file


Mime
View raw message