You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@eagle.apache.org by ji...@apache.org on 2017/02/28 06:38:09 UTC

eagle git commit: [EAGLE-930] UI Notification support

Repository: eagle
Updated Branches:
  refs/heads/master 7bfe55de7 -> 1c90aa46d


[EAGLE-930] UI Notification support

Support alert auto detect and popup notification of current eagle application.

Author: zombieJ <sm...@gmail.com>

Closes #845 from zombieJ/EAGLE-930.


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

Branch: refs/heads/master
Commit: 1c90aa46d23e8ed2f35bddc37e34900392060dac
Parents: 7bfe55d
Author: zombieJ <sm...@gmail.com>
Authored: Tue Feb 28 14:37:56 2017 +0800
Committer: zombieJ <sm...@gmail.com>
Committed: Tue Feb 28 14:37:56 2017 +0800

----------------------------------------------------------------------
 eagle-server/src/main/webapp/app/dev/index.html |  28 ++++
 .../src/main/webapp/app/dev/public/js/app.js    |   7 +-
 .../app/dev/public/js/services/alertSrv.js      |  65 +++++++++
 .../dev/public/js/services/notificationSrv.js   | 144 +++++++++++++++++++
 4 files changed, 243 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/eagle/blob/1c90aa46/eagle-server/src/main/webapp/app/dev/index.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/index.html b/eagle-server/src/main/webapp/app/dev/index.html
index b4dfea6..3408842 100644
--- a/eagle-server/src/main/webapp/app/dev/index.html
+++ b/eagle-server/src/main/webapp/app/dev/index.html
@@ -64,6 +64,7 @@
 
 					<div class="navbar-custom-menu">
 						<ul class="nav navbar-nav">
+							<!-- Time Picker -->
 							<li class="dropdown time-picker" ng-if="Time.pickerType === Time.TIME_RANGE_PICKER">
 								<a data-toggle="dropdown" aria-expanded="false">
 									<span class="fa fa-{{Time.autoRefresh ? 'refresh' : 'calendar'}}"></span>
@@ -84,6 +85,8 @@
 									</li>
 								</ul>
 							</li>
+
+							<!-- Site -->
 							<li class="hover-dropdown">
 								<a>
 									<span ng-if="!Site.current()">
@@ -105,6 +108,29 @@
 									</li>
 								</ul>
 							</li>
+
+							<!-- Notification -->
+							<li class="hover-dropdown">
+								<a>
+									<i class="fa fa-bell"></i>
+									<span ng-if="$notification.list.length" class="label label-warning">
+										{{$notification.list.length}}
+									</span>
+								</a>
+
+								<ul class="dropdown-menu">
+									<li ng-repeat="notification in $notification.list track by $index">
+										<a href="{{notification.url}}" ng-click="$notification.trigger(notification, $event)">
+											{{notification.content}}
+										</a>
+									</li>
+									<li ng-if="!$notification.list.length" class="disabled">
+										<a class="text-gray">No Notification</a>
+									</li>
+								</ul>
+							</li>
+
+							<!-- FAQ -->
 							<li>
 								<a data-toggle="dropdown" aria-expanded="false">
 									<i class="glyphicon glyphicon-question-sign"></i>
@@ -277,6 +303,8 @@
 		<script src="public/js/services/applicationSrv.js" type="text/javascript" charset="utf-8"></script>
 		<script src="public/js/services/uiSrv.js" type="text/javascript" charset="utf-8"></script>
 		<script src="public/js/services/policySrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/notificationSrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/alertSrv.js" type="text/javascript" charset="utf-8"></script>
 
 		<!-- Components -->
 		<script src="public/js/components/main.js" type="text/javascript" charset="utf-8"></script>

http://git-wip-us.apache.org/repos/asf/eagle/blob/1c90aa46/eagle-server/src/main/webapp/app/dev/public/js/app.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/app.js b/eagle-server/src/main/webapp/app/dev/public/js/app.js
index a05ac92..e5b87e8 100644
--- a/eagle-server/src/main/webapp/app/dev/public/js/app.js
+++ b/eagle-server/src/main/webapp/app/dev/public/js/app.js
@@ -273,7 +273,10 @@ var app = {};
 		// ======================================================================================
 		// =                                   Main Controller                                  =
 		// ======================================================================================
-		eagleApp.controller('MainCtrl', function ($scope, $wrapState, $urlRouter, Server, PageConfig, Portal, Widget, Entity, CompatibleEntity, Site, Application, UI, Time, Policy) {
+		eagleApp.controller('MainCtrl', function (
+			$scope, $wrapState, $urlRouter, $notification,
+			Server, PageConfig, Portal, Widget, Entity, CompatibleEntity,
+			Site, Application, UI, Time, Policy, Alert) {
 			window._WrapState = $scope.$wrapState = $wrapState;
 			window._Server = $scope.Server = Server;
 			window._PageConfig = $scope.PageConfig = PageConfig;
@@ -286,6 +289,8 @@ var app = {};
 			window._UI = $scope.UI = UI;
 			window._Time = $scope.Time = Time;
 			window._Policy = $scope.Policy = Policy;
+			window._Notification = $scope.$notification = $notification;
+			window._Alert = $scope.Alert = Alert;
 			$scope.common = common;
 
 			$scope._TRS = window._TRS();

http://git-wip-us.apache.org/repos/asf/eagle/blob/1c90aa46/eagle-server/src/main/webapp/app/dev/public/js/services/alertSrv.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/services/alertSrv.js b/eagle-server/src/main/webapp/app/dev/public/js/services/alertSrv.js
new file mode 100644
index 0000000..9905fa0
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/services/alertSrv.js
@@ -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.
+ */
+
+(function() {
+	'use strict';
+
+	var ALERT_FETCH_LIMIT = 1000 * 60 * 60 * 12;
+	var ALERT_REFRESH_INTERVAL = 1000 * 10;
+	var ALERT_TEMPLATE = '#/site/${siteId}/alert/detail/${alertId}?timestamp=${timestamp}';
+
+	var serviceModule = angular.module('eagle.service');
+
+	serviceModule.service('Alert', function ($notification, Time, CompatibleEntity) {
+		var Alert = {
+			list: null,
+		};
+
+		$notification.getPromise().then(function () {
+			function queryAlerts() {
+				var endTime = new Time();
+				var list = CompatibleEntity.query("LIST", {
+					query: "AlertService",
+					startTime: endTime.clone().subtract(ALERT_FETCH_LIMIT, 'ms'),
+					endTime: endTime
+				});
+				list._then(function () {
+					if (!Alert.list) {
+						Alert.list = list;
+						return;
+					}
+
+					var subList = common.array.minus(list, Alert.list, ['encodedRowkey'], ['encodedRowkey']);
+					Alert.list = list;
+					$.each(subList, function (i, alert) {
+						$notification(alert.alertSubject, common.template(ALERT_TEMPLATE, {
+							siteId: alert.tags.siteId,
+							alertId: alert.tags.alertId,
+							timestamp: alert.timestamp,
+						}));
+					});
+				});
+			}
+
+			queryAlerts();
+			setInterval(queryAlerts, ALERT_REFRESH_INTERVAL);
+		});
+
+		return Alert;
+	});
+})();

http://git-wip-us.apache.org/repos/asf/eagle/blob/1c90aa46/eagle-server/src/main/webapp/app/dev/public/js/services/notificationSrv.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/services/notificationSrv.js b/eagle-server/src/main/webapp/app/dev/public/js/services/notificationSrv.js
new file mode 100644
index 0000000..76f9c45
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/services/notificationSrv.js
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+(function() {
+	'use strict';
+
+	var REFRESH_TIME_LIMIT = 5 * 1000;
+	var PREEMPTIVE_TIME_LIMIT = 8 * 1000;
+	var MAX_NOTIFICATION_COUNT = 100;
+	var serviceModule = angular.module('eagle.service');
+
+	serviceModule.service('$notification', function ($q, $rootScope) {
+		var deferred = $q.defer();
+		var promised = false;
+		var id = +new Date();
+		var lastHookTime = +new Date();
+		var instanceId = 0;
+		var lastInstance;
+
+		function notification(content, url) {
+			if (!promised) return;
+
+			instanceId += 1;
+
+			// Add notification in queue
+			var config = {
+				content: content,
+				url: url,
+				id: instanceId,
+			};
+			notification.list.push(config);
+			notification.list = notification.list.slice(0, MAX_NOTIFICATION_COUNT);
+
+			// Popup notification
+			var count = notification.list.length;
+			var instance = new Notification((count > 1 ? '[' + count + '] ' : '') + 'Apache Eagle:', {
+				tag: 'eagle',
+				body: content,
+				icon: 'public/images/favicon.png',
+				renotify: true,
+			});
+			instance.onclick = function () {
+				window.focus();
+				notification.trigger(config);
+
+				if (lastInstance === instance) lastInstance = null;
+				instance.close();
+
+				$rootScope.$apply();
+			};
+
+			// Close notification
+			setTimeout(function () {
+				if (lastInstance === instance) {
+					lastInstance = null;
+					instance.close();
+				}
+			}, 5000);
+			lastInstance = instance;
+		}
+
+		function uniqueNotification() {
+			function loopListener() {
+				var hooker = common.parseJSON(localStorage.getItem('notificationId'), null);
+				if (promised || !hooker || (+new Date()) - (hooker.lastHookTime || 0) > PREEMPTIVE_TIME_LIMIT) {
+					promised = true;
+					deferred.resolve();
+					lastHookTime = +new Date();
+					localStorage.setItem('notificationId', JSON.stringify({
+						id: id,
+						lastHookTime: lastHookTime,
+					}));
+				}
+			}
+
+			setInterval(loopListener, REFRESH_TIME_LIMIT);
+			loopListener();
+
+			$(window).bind("beforeunload", function() {
+				var hooker = common.parseJSON(localStorage.getItem('notificationId'), {});
+				if (hooker.id === id) {
+					localStorage.removeItem('notificationId');
+				}
+				if (lastInstance) {
+					lastInstance.close();
+					lastInstance = null;
+				}
+			});
+		}
+
+		if (!'Notification' in window || !'localStorage' in window) {
+			// Notification not support
+			console.warn('Browser do not support Notification api. Ignore...');
+		} else {
+			// Check notification state;
+			if (Notification.permission === 'granted') {
+				// promised = true;
+				uniqueNotification();
+			} else if (Notification.permission !== 'denied') {
+				Notification.requestPermission().then(function(permission) {
+					if (permission === "granted") {
+						uniqueNotification();
+					} else {
+						console.warn('User deny the notification.');
+					}
+				});
+			} else {
+				console.warn('Web Notification initialization denied. Ignore eagle web notification.');
+			}
+		}
+
+		notification.list = [];
+
+		notification.trigger = function (config, event) {
+			notification.list = common.array.remove(config.id, notification.list, ['id']);
+
+			if (!event || !event.ctrlKey) {
+				location.href = config.url;
+				if (event) event.preventDefault();
+			}
+		};
+
+		notification.getPromise = function () {
+			return deferred.promise;
+		};
+
+		return notification;
+	});
+})();