Return-Path: X-Original-To: apmail-eagle-commits-archive@minotaur.apache.org Delivered-To: apmail-eagle-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4278B18D76 for ; Fri, 26 Feb 2016 21:26:37 +0000 (UTC) Received: (qmail 33917 invoked by uid 500); 26 Feb 2016 21:26:37 -0000 Delivered-To: apmail-eagle-commits-archive@eagle.apache.org Received: (qmail 33887 invoked by uid 500); 26 Feb 2016 21:26:37 -0000 Mailing-List: contact commits-help@eagle.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@eagle.incubator.apache.org Delivered-To: mailing list commits@eagle.incubator.apache.org Received: (qmail 33878 invoked by uid 99); 26 Feb 2016 21:26:37 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Feb 2016 21:26:37 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 95BF11A020D for ; Fri, 26 Feb 2016 21:26:36 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -3.549 X-Spam-Level: X-Spam-Status: No, score=-3.549 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.329] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id trrJ4k5FVtDz for ; Fri, 26 Feb 2016 21:26:22 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id 6012B5FB9C for ; Fri, 26 Feb 2016 21:26:20 +0000 (UTC) Received: (qmail 32436 invoked by uid 99); 26 Feb 2016 21:26:19 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Feb 2016 21:26:19 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 6A8C0E03C0; Fri, 26 Feb 2016 21:26:19 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: hdendukuri@apache.org To: commits@eagle.incubator.apache.org Date: Fri, 26 Feb 2016 21:26:22 -0000 Message-Id: In-Reply-To: <3e00d7d5028547c283bfe80fcc09cd2e@git.apache.org> References: <3e00d7d5028547c283bfe80fcc09cd2e@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [4/9] incubator-eagle git commit: EAGLE-139 EAGLE-163 Eagle UI Modularization and fix bugs in policy extensions http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/feature/userProfile/controller.js ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/userProfile/controller.js b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/controller.js new file mode 100644 index 0000000..f048a85 --- /dev/null +++ b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/controller.js @@ -0,0 +1,268 @@ +/* + * 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 featureControllers = angular.module('featureControllers'); + var feature = featureControllers.register("userProfile"); + + // ============================================================== + // = Function = + // ============================================================== + + // ============================================================== + // = User Profile = + // ============================================================== + + // ======================== Profile List ======================== + //feature.navItem("list", "User Profiles", "graduation-cap"); + feature.controller('list', function(PageConfig, Site, $scope, $interval, Entities) { + PageConfig.pageSubTitle = Site.current().tags.site; + + $scope.common = common; + $scope.algorithms = []; + + // ======================================== Algorithms ======================================== + $scope.algorithmEntity = {}; + Entities.queryEntities("AlertDefinitionService", {site: Site.current().tags.site, dataSource: "userProfile"})._promise.then(function(data) { + $scope.algorithmEntity = common.getValueByPath(data, "obj[0]"); + $scope.algorithmEntity.policy = common.parseJSON($scope.algorithmEntity.policyDef); + }); + + // ======================================= User profile ======================================= + $scope.profileList = Entities.queryEntities("MLModelService", {site: Site.current().tags.site}, ["user", "algorithm", "content", "version"]); + $scope.profileList._promise.then(function() { + var _algorithms = {}; + var _users = {}; + + // Map user + $.each($scope.profileList, function(i, unit) { + _algorithms[unit.tags.algorithm] = unit.tags.algorithm; + var _user = _users[unit.tags.user] = _users[unit.tags.user] || {user: unit.tags.user}; + _user[unit.tags.algorithm] = { + version: unit.version + }; + + // DE + if(unit.tags.algorithm === "DE") { + var _statistics = common.parseJSON(unit.content); + _statistics = common.getValueByPath(_statistics, "statistics", []); + _user[unit.tags.algorithm].topCommands = $.map(common.array.top(_statistics, "mean"), function(command) { + return command.commandName; + }); + } + }); + + // Map algorithms + $scope.algorithms = $.map(_algorithms, function(algorithm) { + return algorithm; + }).sort(); + + $scope.profileList.splice(0); + $scope.profileList.push.apply($scope.profileList, common.map.toArray(_users)); + }); + + // =========================================== Task =========================================== + $scope.tasks = []; + function _loadTasks() { + var _tasks = Entities.queryEntities("ScheduleTaskService", { + site: Site.current().tags.site, + _pageSize: 100, + _duration: 1000 * 60 * 60 * 24 * 14, + __ETD: 1000 * 60 * 60 * 24 + }); + _tasks._promise.then(function() { + $scope.tasks.splice(0); + $scope.tasks.push.apply($scope.tasks, _tasks); + + // Duration + $.each($scope.tasks, function(i, data) { + if(data.timestamp && data.updateTime) { + var _ms = (new moment(data.updateTime)).diff(new moment(data.timestamp)); + var _d = moment.duration(_ms); + data._duration = Math.floor(_d.asHours()) + moment.utc(_ms).format(":mm:ss"); + data.duration = _ms; + } else { + data._duration = "--"; + } + }); + }); + } + + $scope.runningTaskCount = function () { + return common.array.count($scope.tasks, "INITIALIZED", "status") + + common.array.count($scope.tasks, "PENDING", "status") + + common.array.count($scope.tasks, "EXECUTING", "status"); + }; + + // Create task + $scope.updateTask = function() { + $.dialog({ + title: "Confirm", + content: "Do you want to update now?", + confirm: true + }, function(ret) { + if(!ret) return; + + var _entity = { + status: "INITIALIZED", + detail: "Newly created command", + tags: { + site: Site.current().tags.site, + type: "USER_PROFILE_TRAINING" + }, + timestamp: +new Date() + }; + Entities.updateEntity("ScheduleTaskService", _entity, {timestamp: false})._promise.success(function(data) { + if(!Entities.dialog(data)) { + _loadTasks(); + } + }); + }); + }; + + // Show detail + $scope.showTaskDetail = function(task) { + var _content = $("
").text(task.detail);
+
+			var $mdl = $.dialog({
+				title: "Detail",
+				content: _content
+			});
+
+			_content.click(function(e) {
+				if(!e.ctrlKey) return;
+
+				$.dialog({
+					title: "Confirm",
+					content: "Remove this task?",
+					confirm: true
+				}, function(ret) {
+					if(!ret) return;
+
+					$mdl.modal('hide');
+					Entities.deleteEntity("ScheduleTaskService", task)._promise.then(function() {
+						_loadTasks();
+					});
+				});
+			});
+		};
+
+		_loadTasks();
+		var _loadInterval = $interval(_loadTasks, app.time.refreshInterval);
+		$scope.$on('$destroy',function(){
+			$interval.cancel(_loadInterval);
+		});
+	});
+
+	// ======================= Profile Detail =======================
+	feature.controller('detail', function(PageConfig, Site, $scope, $wrapState, Entities) {
+		PageConfig.pageTitle = "User Profile";
+		PageConfig.pageSubTitle = Site.current().tags.site;
+		PageConfig
+			.addNavPath("User Profile", "/userProfile/list")
+			.addNavPath("Detail");
+
+		$scope.user = $wrapState.param.filter;
+
+		// User profile
+		$scope.profiles = {};
+		$scope.profileList = Entities.queryEntities("MLModelService", {site: Site.current().tags.site, user: $scope.user});
+		$scope.profileList._promise.then(function() {
+			$.each($scope.profileList, function(i, unit) {
+				unit._content = common.parseJSON(unit.content);
+				$scope.profiles[unit.tags.algorithm] = unit;
+			});
+
+			// DE
+			if($scope.profiles.DE) {
+				console.log($scope.profiles.DE);
+
+				$scope.profiles.DE._chart = {};
+
+				$scope.profiles.DE.estimates = {};
+				$.each($scope.profiles.DE._content, function(key, value) {
+					if(key !== "statistics") {
+						$scope.profiles.DE.estimates[key] = value;
+					}
+				});
+
+				var _meanList = [];
+				var _stddevList = [];
+
+				$.each($scope.profiles.DE._content.statistics, function(i, unit) {
+					_meanList[i] = {
+						x: unit.commandName,
+						y: unit.mean
+					};
+					_stddevList[i] = {
+						x: unit.commandName,
+						y: unit.stddev
+					};
+				});
+				$scope.profiles.DE._chart.series = [
+					{
+						key: "mean",
+						values: _meanList
+					},
+					{
+						key: "stddev",
+						values: _stddevList
+					}
+				];
+
+				// Percentage table list
+				$scope.profiles.DE.meanList = [];
+				var _total = common.array.sum($scope.profiles.DE._content.statistics, "mean");
+				$.each($scope.profiles.DE._content.statistics, function(i, unit) {
+					$scope.profiles.DE.meanList.push({
+						command: unit.commandName,
+						percentage: unit.mean / _total
+					});
+				});
+			}
+
+			// EigenDecomposition
+			if($scope.profiles.EigenDecomposition && $scope.profiles.EigenDecomposition._content.principalComponents) {
+				$scope.profiles.EigenDecomposition._chart = {
+					series: [],
+				};
+
+				$.each($scope.profiles.EigenDecomposition._content.principalComponents, function(z, grp) {
+					var _line = [];
+					$.each(grp, function(x, y) {
+						_line.push([x,y,z]);
+					});
+
+					$scope.profiles.EigenDecomposition._chart.series.push({
+						data: _line
+					});
+				});
+			}
+		});
+
+		// UI
+		$scope.showRawData = function(content) {
+			$.dialog({
+				title: "Raw Data",
+				content: $("
").text(content)
+			});
+		};
+	});
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/detail.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/detail.html b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/detail.html
new file mode 100644
index 0000000..0f94e03
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/detail.html
@@ -0,0 +1,87 @@
+
+
+
+ +

+ {{user}} +

+
+
+
+
+
User
{{user}}
+
Site
{{Site.current().tags.site}}
+
+
+
Other Info
N/A
+
+
+ +
+ +
+
+
+ + + http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/list.html ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/list.html b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/list.html new file mode 100644 index 0000000..2f14479 --- /dev/null +++ b/eagle-webservice/src/main/webapp/app/public/feature/userProfile/page/list.html @@ -0,0 +1,138 @@ + +
+
+ +

+ User Profiles + Detail +

+
+ Update +
+
+
+ +
+ + + + + + + + + + + + + +
NameFeature
{{algorithm.name}}{{algorithm.features}}
+
+
+ + +

+ + Loading... +

+ +
+ + + + + + + + + + + + + + + +
UserMost Predominat Feature
+ {{item.user}} + + {{item.DE.topCommands.slice(0,3).join(", ")}} + + Detail +
+
+
+
+ + + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/images/favicon_white.png ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/images/favicon_white.png b/eagle-webservice/src/main/webapp/app/public/images/favicon_white.png new file mode 100644 index 0000000..9879e92 Binary files /dev/null and b/eagle-webservice/src/main/webapp/app/public/images/favicon_white.png differ http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/js/app.config.js ---------------------------------------------------------------------- diff --git a/eagle-webservice/src/main/webapp/app/public/js/app.config.js b/eagle-webservice/src/main/webapp/app/public/js/app.config.js index f18b846..1e6fd79 100644 --- a/eagle-webservice/src/main/webapp/app/public/js/app.config.js +++ b/eagle-webservice/src/main/webapp/app/public/js/app.config.js @@ -1,77 +1,104 @@ -/* - * 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'; - - app.config = { - // ============================================================================ - // = URLs = - // ============================================================================ - urls: { - HOST: '..', - - updateEntity: 'rest/entities?serviceName=${serviceName}', - queryEntity: 'rest/entities/rowkey?serviceName=${serviceName}&value=${encodedRowkey}', - queryEntities: 'rest/list?query=${serviceName}[${condition}]{${values}}&pageSize=100000', - deleteEntity: 'rest/entities/delete?serviceName=${serviceName}&byId=true', - deleteEntities: 'rest/entities?query=${serviceName}[${condition}]{*}&pageSize=100000', - - queryGroup: 'rest/list?query=${serviceName}[${condition}]<${groupBy}>{${values}}&pageSize=100000', - querySeries: 'rest/list?query=${serviceName}[${condition}]<${groupBy}>{${values}}&pageSize=100000&timeSeries=true&intervalmin=${intervalmin}', - - query: 'rest/', - - userProfile: 'rest/authentication', - logout: 'logout', - }, - - // ============================================================================ - // = Data Sources = - // ============================================================================ - dataSource: { - uiInvisibleList: ["userProfile"], - }, - }; - - // ============================================================================ - // = URLs = - // ============================================================================ - app.getURL = function(name, kvs) { - var _host = localStorage.getItem("HOST") || app.config.urls.HOST; - var _path = app.config.urls[name]; - if(!_path) throw "URL:'" + name + "' not exist!"; - var _url = (_host ? _host + "/" : '') + _path; - if(kvs !== undefined) { - _url = common.template(_url, kvs); - } - return _url; - }; - - app._Host = function(host) { - if(host) { - localStorage.setItem("HOST", host); - return app; - } - return localStorage.getItem("HOST"); - }; - app._Host.clear = function() { - localStorage.removeItem("HOST"); - }; - app._Host.sample = "http://localhost:9099/eagle-service"; +/* + * 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'; + + app.config = { + // ============================================================================ + // = URLs = + // ============================================================================ + urls: { + HOST: '..', + + updateEntity: 'rest/entities?serviceName=${serviceName}', + queryEntity: 'rest/entities/rowkey?serviceName=${serviceName}&value=${encodedRowkey}', + queryEntities: 'rest/list?query=${serviceName}[${condition}]{${values}}&pageSize=100000', + deleteEntity: 'rest/entities/delete?serviceName=${serviceName}&byId=true', + deleteEntities: 'rest/entities?query=${serviceName}[${condition}]{*}&pageSize=100000', + + queryGroup: 'rest/list?query=${serviceName}[${condition}]<${groupBy}>{${values}}&pageSize=100000', + querySeries: 'rest/list?query=${serviceName}[${condition}]<${groupBy}>{${values}}&pageSize=100000&timeSeries=true&intervalmin=${intervalmin}', + + query: 'rest/', + + userProfile: 'rest/authentication', + logout: 'logout', + + DELETE_HOOK: { + FeatureDescService: 'rest/module/feature?feature=${feature}', + ApplicationDescService: 'rest/module/application?application=${application}', + SiteDescService: 'rest/module/site?site=${site}' + }, + UPDATE_HOOK: { + SiteDescService: 'rest/module/siteApplication' + } + }, + }; + + // ============================================================================ + // = URLs = + // ============================================================================ + app.getURL = function(name, kvs) { + var _host = localStorage.getItem("HOST") || app.config.urls.HOST; + var _path = app.config.urls[name]; + if(!_path) throw "URL:'" + name + "' not exist!"; + var _url = (_host ? _host + "/" : '') + _path; + if(kvs !== undefined) { + _url = common.template(_url, kvs); + } + return _url; + }; + + function getHookURL(hookType, serviceName) { + var _path = app.config.urls[hookType][serviceName]; + if(!_path) return null; + + var _host = localStorage.getItem("HOST") || app.config.urls.HOST; + var _url = (_host ? _host + "/" : '') + _path; + return _url; + } + + /*** + * Eagle support delete function to process special entity delete. Which will delete all the relative entity. + * @param serviceName + */ + app.getDeleteURL = function(serviceName) { + return getHookURL('DELETE_HOOK', serviceName); + }; + + /*** + * Eagle support update function to process special entity update. Which will update all the relative entity. + * @param serviceName + */ + app.getUpdateURL = function(serviceName) { + return getHookURL('UPDATE_HOOK', serviceName); + }; + + app._Host = function(host) { + if(host) { + localStorage.setItem("HOST", host); + return app; + } + return localStorage.getItem("HOST"); + }; + app._Host.clear = function() { + localStorage.removeItem("HOST"); + }; + app._Host.sample = "http://localhost:9099/eagle-service"; })(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/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 777844d..e9dfb2a 100644 --- a/eagle-webservice/src/main/webapp/app/public/js/app.js +++ b/eagle-webservice/src/main/webapp/app/public/js/app.js @@ -18,693 +18,467 @@ var app = {}; -/* App Module */ -var eagleApp = angular.module('eagleApp', ['ngRoute', 'ngCookies', 'damControllers']); - -eagleApp.config(function($routeProvider) { +(function() { 'use strict'; - $routeProvider.when('/dam/summary', { - templateUrl : 'partials/dam/summary.html', - controller : 'summaryCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - // Authorization - }).when('/dam/login', { - templateUrl : 'partials/dam/login.html', - controller : 'authLoginCtrl', - access: {skipCheck: true}, - - // Policy - }).when('/dam/policyList', { - templateUrl : 'partials/dam/policyList.html', - controller : 'policyListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/policyList/:dataSource', { - templateUrl : 'partials/dam/policyList.html', - controller : 'policyListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/policyDetail/', { - templateUrl : 'partials/dam/policyDetail.html', - controller : 'policyDetailCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/policyDetail/:encodedRowkey', { - templateUrl : 'partials/dam/policyDetail.html', - controller : 'policyDetailCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/policyEdit/:encodedRowkey', { - templateUrl : 'partials/dam/policyEdit.html', - controller : 'policyEditCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/policyCreate/', { - templateUrl : 'partials/dam/policyEdit.html', - controller : 'policyCreateCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - // Alert - }).when('/dam/alertList', { - templateUrl : 'partials/dam/alertList.html', - controller : 'alertListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/alertList/:dataSource', { - templateUrl : 'partials/dam/alertList.html', - controller : 'alertListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/alertDetail/:encodedRowkey', { - templateUrl : 'partials/dam/alertDetail.html', - controller : 'alertDetailCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - // Stream - }).when('/dam/streamList', { - templateUrl : 'partials/dam/streamList.html', - controller : 'streamListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - // Site - }).when('/dam/siteList', { - templateUrl : 'partials/dam/siteList.html', - controller : 'siteListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - access: {roles: ["ROLE_ADMIN"]}, - - // Sensitivity - }).when('/dam/sensitivitySummary', { - templateUrl : 'partials/dam/sensitivitySummary.html', - controller : 'sensitivitySummaryCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/sensitivity/:dataSrc', { - templateUrl : 'partials/dam/sensitivity.html', - controller : 'sensitivityCtrl', - reloadOnSearch: false, - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - // User Profile - }).when('/dam/userProfileList', { - templateUrl : 'partials/dam/userProfileList.html', - controller : 'userProfileListCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - }).when('/dam/userProfileDetail/:user', { - templateUrl : 'partials/dam/userProfileDetail.html', - controller : 'userProfileDetailCtrl', - resolve: { - site: function(Site) {return Site._promise();}, - auth: function(Authorization) {return Authorization._promise();}, - }, - - }).otherwise({ - redirectTo : '/dam/summary' + /* App Module */ + var eagleApp = angular.module('eagleApp', ['ngRoute', 'ngAnimate', 'ui.router', 'eagleControllers', 'featureControllers', 'eagle.service']); + + // ====================================================================================== + // = Feature Module = + // ====================================================================================== + var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m; + var FN_ARG_SPLIT = /,/; + var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; + var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; + + var featureControllers = angular.module('featureControllers', ['ui.bootstrap', 'eagle.components']); + var featureControllerCustomizeHtmlTemplate = {}; + var featureControllerProvider; + var featureProvider; + + featureControllers.config(function ($controllerProvider, $provide) { + featureControllerProvider = $controllerProvider; + featureProvider = $provide; }); -}); - -eagleApp.service('globalContent', function(Entities, $rootScope, $route, $location) { - 'use strict'; - - var content = { - pageTitle: "", - pageSubTitle: "", - pageList: [], - navPath: [], - navMapping: {}, - - hideSite: false, - lockSite: false, - dataSrcList: [], + featureControllers.service("Feature", function($wrapState, PageConfig, ConfigPageConfig, FeaturePageConfig) { + var _features = {}; + var _services = {}; - setConfig: function(config) { - // Clean up - content.navPath = []; - - // Fill configuration - $.extend(content, config); - }, - }; - - return content; -}); - -// Site -eagleApp.service('Site', function(Authorization, Entities, $rootScope, $route, $location, $q) { - 'use strict'; - - var _currentSite; - var content = {}; - - content.list = []; - content.list.set = {}; - content.dataSrcList = []; - - content.current = function(site) { - if(site) { - var _prev = _currentSite; - _currentSite = site; - - // Broadcast if site update - if(!_prev || _prev.name !== _currentSite.name) { - if(sessionStorage) { - sessionStorage.setItem("site", _currentSite.name); - } + var Feature = function(name, version) { + this.name = name; + this.version = version; + this.features = {}; + }; - if(!content.hideSite) $route.reload(); + /*** + * Inner function. Replace the dependency of constructor. + * @param constructor + * @private + */ + Feature.prototype._replaceDependencies = function(constructor) { + var i, srvName; + var _constructor, _$inject; + var fnText, argDecl; + + if($.isArray(constructor)) { + _constructor = constructor[constructor.length - 1]; + _$inject = constructor.slice(0, -1); + } else if(constructor.$inject) { + _constructor = constructor; + _$inject = constructor.$inject; + } else { + _$inject = []; + _constructor = constructor; + fnText = constructor.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + $.each(argDecl[1].split(FN_ARG_SPLIT), function(i, arg) { + arg.replace(FN_ARG, function(all, underscore, name) { + _$inject.push(name); + }); + }); } - } - return _currentSite; - }; - content.find = function(siteName) { - return common.array.find(siteName, content.list, "name"); - }; - content.url = function(site, url) { - if(arguments.length == 1) { - url = site; - } else { - content.current(site); - } - $location.url(url); + _constructor.$inject = _$inject; - if ($rootScope.$$phase != '$apply' && $rootScope.$$phase != '$digest') { - $rootScope.$apply(); - } - }; - - var _promise; - content.refresh = function() { - content.list = []; - content.list.set = {}; - - content.dataSrcList = Entities.queryEntities("AlertDataSourceService", ''); - content.dataSrcList._promise.success(function() { - $.each(content.dataSrcList, function(i, dataSrc) { - var _site = content.list.set[dataSrc.tags.site]; - if(!_site) { - _site = content.list.set[dataSrc.tags.site] = { - name: dataSrc.tags.site, - dataSrcList: [] - }; - _site.dataSrcList.find = function(dataSrcName) { - return common.array.find(dataSrcName, _site.dataSrcList, "tags.dataSource"); - }; - content.list.push(_site); - } - _site.dataSrcList.push(dataSrc); + for(i = 0 ; i < _$inject.length ; i += 1) { + srvName = _$inject[i]; + _$inject[i] = this.features[srvName] || _$inject[i]; + } - // UI visible check - if($.inArray(dataSrc.tags.dataSource, app.config.dataSource.uiInvisibleList) !== -1) { - dataSrc.hide = true; - } - }); + return _constructor; + }; - if(sessionStorage && content.find(sessionStorage.getItem("site"))) { - content.current(content.find(sessionStorage.getItem("site"))); + /*** + * Register a common service for feature usage. Common service will share between the feature. If you are coding customize feature, use 'Feature.service' is the better way. + * @param name + * @param constructor + */ + Feature.prototype.commonService = function(name, constructor) { + if(!_services[name]) { + featureProvider.service(name, constructor); + _services[name] = this.name; } else { - content.current(content.list[0]); + throw "Service '" + name + "' has already be registered by feature '" + _services[name] + "'"; } - }); + }; - _promise = content.dataSrcList._promise; - return _promise; - }; + /*** + * Register a service for feature usage. + * @param name + * @param constructor + */ + Feature.prototype.service = function(name, constructor) { + var _serviceName; + if(!this.features[name]) { + _serviceName = "__FEATURE_" + this.name + "_" + name; + featureProvider.service(_serviceName, this._replaceDependencies(constructor)); + this.features[name] = _serviceName; + } else { + console.warn("Service '" + name + "' has already be registered."); + } + }; - content._promise = function() { - if(!_promise) { - content.refresh(); - } - return _promise; - }; + /*** + * Create an navigation item in left navigation bar + * @param path + * @param title + * @param icon use Font Awesome. Needn't with 'fa fa-'. + */ + Feature.prototype.navItem = function(path, title, icon) { + title = title || path; + icon = icon || "question"; + + FeaturePageConfig.addNavItem(this.name, { + icon: icon, + title: title, + url: "#/" + this.name + "/" + path + }); + }; - return content; -}); + /*** + * Register a controller. + * @param name + * @param constructor + */ + Feature.prototype.controller = function(name, constructor, htmlTemplatePath) { + var _name = this.name + "_" + name; + + // Replace feature registered service + constructor = this._replaceDependencies(constructor); + + // Register controller + featureControllerProvider.register(_name, constructor); + if(htmlTemplatePath) { + featureControllerCustomizeHtmlTemplate[_name] = htmlTemplatePath; + } -// Authorization -eagleApp.service('Authorization', function($http, $location, $cookies) { - 'use strict'; + return _name; + }; - $http.defaults.withCredentials = true; - - var _path = ""; - var _userProfile = null; - - var content = { - isLogin: true, // Status mark. Work for UI status check, changed when eagle api return 403 authorization failure. - needLogin: function() { - _path = _path || $location.path(); - content.isLogin = false; - $location.path("/dam/login"); - }, - login: function(username, password) { - var _hash = btoa(username + ':' + password); - return $http({ - url : app.getURL('userProfile'), - method : "GET", - headers: { - 'Authorization': "Basic " + _hash - } - }).then(function() { - content.isLogin = true; - return true; - }, function() { - return false; - }); - }, - logout: function() { - $http({ - url : app.getURL('logout'), - method : "GET", - }); - }, - path: function(path) { - if(typeof path === "string") { - _path = path; - } else if(path === true) { - $location.path(_path || ""); - _path = ""; + /*** + * Register a configuration controller for admin usage. + * @param name + * @param constructor + */ + Feature.prototype.configController = function(name, constructor, htmlTemplatePath) { + var _name = "config_" + this.name + "_" + name; + + // Replace feature registered service + constructor = this._replaceDependencies(constructor); + + // Register controller + featureControllerProvider.register(_name, constructor); + if(htmlTemplatePath) { + featureControllerCustomizeHtmlTemplate[_name] = htmlTemplatePath; } - }, - }; - - var _promise; - content.userProfile = {}; - content.isRole = function(role) { - if(!content.userProfile.roles) return null; - - return content.userProfile.roles[role] === true; - }; - - content.refresh = function() { - _promise = $http({ - url : app.getURL('userProfile'), - method : "GET", - }).then(function(data) { - content.userProfile = data.data; - - // Role - content.userProfile.roles = {}; - $.each(content.userProfile.authorities, function(i, role) { - content.userProfile.roles[role.authority] = true; - }); - }); - return _promise; - }; - content._promise = function() { - if(!_promise) { - content.refresh(); - } - return _promise; - }; + return _name; + }; - return content; -}); + /*** + * Create an navigation item in left navigation bar for admin configuraion page + * @param path + * @param title + * @param icon use Font Awesome. Needn't with 'fa fa-'. + */ + Feature.prototype.configNavItem = function(path, title, icon) { + title = title || path; + icon = icon || "question"; + + ConfigPageConfig.addNavItem(this.name, { + icon: icon, + title: title, + url: "#/config/" + this.name + "/" + path + }); + }; -eagleApp.service('Entities', function($http, $q, $rootScope, $location, Authorization) { - 'use strict'; + // Register + featureControllers.register = Feature.register = function(featureName) { + _features[featureName] = _features[featureName] || new Feature(featureName); + return _features[featureName]; + }; - // Query - function _query(name, kvs) { - kvs = kvs || {}; - var _list = []; - var _condition = kvs._condition || {}; - var _addtionalCondition = _condition.additionalCondition || {}; - var _startTime, _endTime; - var _startTimeStr, _endTimeStr; - - // Initial - // > Condition - delete kvs._condition; - if(_condition) { - kvs.condition = _condition.condition; - } + // Page go + Feature.go = function(feature, page, filter) { + if(!filter) { + $wrapState.go("page", { + feature: feature, + page: page + }, 2); + } else { + $wrapState.go("pageFilter", { + feature: feature, + page: page, + filter: filter + }, 2); + } + }; - // > Values - if(!kvs.values) { - kvs.values = "*"; - } else if($.isArray(kvs.values)) { - kvs.values = $.map(kvs.values, function(field) { - return (field[0] === "@" ? '' : '@') + field; - }).join(","); - } + return Feature; + }); - var _url = app.getURL(name, kvs); + // ====================================================================================== + // = Router config = + // ====================================================================================== + eagleApp.config(function ($stateProvider, $urlRouterProvider) { + // Resolve + function _resolve(config) { + config = config || {}; - // Fill special parameters - // > Query by time duration - if(_addtionalCondition._duration) { - _endTime = app.time.now(); - _startTime = _endTime.clone().subtract(_addtionalCondition._duration, "ms"); + var resolve = { + Site: function (Site) { + return Site._promise(); + }, + Authorization: function (Authorization) { + if(!config.roleType) { + return Authorization._promise(); + } else { + return Authorization.rolePromise(config.roleType); + } + }, + Application: function (Application) { + return Application._promise(); + } + }; + + if(config.featureCheck) { + resolve._navigationCheck = function($q, $wrapState, Site, Application) { + var _deferred = $q.defer(); + + $q.all(Site._promise(), Application._promise()).then(function() { + var _match, i, tmpApp; + var _site = Site.current(); + var _app = Application.current(); + + // Check application + if(_site && ( + !_app || + !_site.applicationList.set[_app.tags.application] || + !_site.applicationList.set[_app.tags.application].enabled + ) + ) { + _match = false; + + for(i = 0 ; i < _site.applicationGroupList.length ; i += 1) { + tmpApp = _site.applicationGroupList[i].enabledList[0]; + if(tmpApp) { + _app = Application.current(tmpApp); + _match = true; + break; + } + } + + if(!_match) { + _app = null; + Application.current(null); + } + } + }).finally(function() { + _deferred.resolve(); + }); - // Debug usage. Extend more time duration for end time - if(_addtionalCondition.__ETD) { - _endTime.add(_addtionalCondition.__ETD, "ms"); + return _deferred.promise; + }; } - _addtionalCondition._startTime = _startTime; - _addtionalCondition._endTime = _endTime; - - _startTimeStr = _startTime.format("YYYY-MM-DD HH:mm:ss"); - _endTimeStr = _endTime.clone().add(1, "s").format("YYYY-MM-DD HH:mm:ss"); + return resolve; + } - _url += "&startTime=" + _startTimeStr + "&endTime=" + _endTimeStr; - } else if(_addtionalCondition._startTime && _addtionalCondition._endTime) { - _startTimeStr = _addtionalCondition._startTime.format("YYYY-MM-DD HH:mm:ss"); - _endTimeStr = _addtionalCondition._endTime.clone().add(1, "s").format("YYYY-MM-DD HH:mm:ss"); + // Router + var _featureBase = { + templateUrl: function ($stateParams) { + var _htmlTemplate = featureControllerCustomizeHtmlTemplate[$stateParams.feature + "_" + $stateParams.page]; + return "public/feature/" + $stateParams.feature + "/page/" + (_htmlTemplate || $stateParams.page) + ".html?_=" + Math.random(); + }, + controllerProvider: function ($stateParams) { + return $stateParams.feature + "_" + $stateParams.page; + }, + resolve: _resolve({featureCheck: true}), + pageConfig: "FeaturePageConfig" + }; - _url += "&startTime=" + _startTimeStr + "&endTime=" + _endTimeStr; - } + $urlRouterProvider.otherwise("/landing"); + $stateProvider + // =================== Landing =================== + .state('landing', { + url: "/landing", + templateUrl: "partials/landing.html?_=" + Math.random(), + controller: "landingCtrl", + resolve: _resolve({featureCheck: true}) + }) + + // ================ Authorization ================ + .state('login', { + url: "/login", + templateUrl: "partials/login.html?_=" + Math.random(), + controller: "authLoginCtrl", + access: {skipCheck: true} + }) + + // ================ Configuration ================ + // Site + .state('configSite', { + url: "/config/site", + templateUrl: "partials/config/site.html?_=" + Math.random(), + controller: "configSiteCtrl", + pageConfig: "ConfigPageConfig", + resolve: _resolve({roleType: 'ROLE_ADMIN'}) + }) + + // Application + .state('configApplication', { + url: "/config/application", + templateUrl: "partials/config/application.html?_=" + Math.random(), + controller: "configApplicationCtrl", + pageConfig: "ConfigPageConfig", + resolve: _resolve({roleType: 'ROLE_ADMIN'}) + }) + + // Feature + .state('configFeature', { + url: "/config/feature", + templateUrl: "partials/config/feature.html?_=" + Math.random(), + controller: "configFeatureCtrl", + pageConfig: "ConfigPageConfig", + resolve: _resolve({roleType: 'ROLE_ADMIN'}) + }) + + // Feature configuration page + .state('configFeatureDetail', $.extend({url: "/config/:feature/:page"}, { + templateUrl: function ($stateParams) { + var _htmlTemplate = featureControllerCustomizeHtmlTemplate[$stateParams.feature + "_" + $stateParams.page]; + return "public/feature/" + $stateParams.feature + "/page/" + (_htmlTemplate || $stateParams.page) + ".html?_=" + Math.random(); + }, + controllerProvider: function ($stateParams) { + return "config_" + $stateParams.feature + "_" + $stateParams.page; + }, + pageConfig: "ConfigPageConfig", + resolve: _resolve({roleType: 'ROLE_ADMIN'}) + })) + + // =================== Feature =================== + // Dynamic feature page + .state('page', $.extend({url: "/:feature/:page"}, _featureBase)) + .state('pageFilter', $.extend({url: "/:feature/:page/:filter"}, _featureBase)) + ; + }); - // > Query contains metric name - if(_addtionalCondition._metricName) { - _url += "&metricName=" + _addtionalCondition._metricName; - } + eagleApp.filter('parseJSON', function () { + return function (input, defaultVal) { + return common.parseJSON(input, defaultVal); + }; + }); - // > Customize page size - if(_addtionalCondition._pageSize) { - _url = _url.replace(/pageSize=\d+/, "pageSize=" + _addtionalCondition._pageSize); - } + eagleApp.filter('split', function () { + return function (input, regex) { + return input.split(regex); + }; + }); - // AJAX - var canceler = $q.defer(); - _list._promise = $http.get(_url, {timeout: canceler.promise}).success(function(data) { - _list.push.apply(_list, data.obj); - }); - _list._promise.abort = function() { - canceler.resolve(); + eagleApp.filter('reverse', function () { + return function (items) { + return items.slice().reverse(); }; + }); - _list._promise.then(function() {}, function(data) { - if(data.status === 403) { - Authorization.needLogin(); + // ====================================================================================== + // = Main Controller = + // ====================================================================================== + eagleApp.controller('MainCtrl', function ($scope, $wrapState, $http, $injector, PageConfig, FeaturePageConfig, Site, Authorization, Entities, nvd3, Application, Feature, UI) { + window.site = $scope.Site = Site; + window.auth = $scope.Auth = Authorization; + window.entities = $scope.Entities = Entities; + window.application = $scope.Application = Application; + window.pageConfig = $scope.PageConfig = PageConfig; + window.featurePageConfig = $scope.FeaturePageConfig = FeaturePageConfig; + window.feature = $scope.Feature = Feature; + window.ui = $scope.UI = UI; + window.nvd3 = nvd3; + $scope.app = app; + $scope.common = common; + + Object.defineProperty(window, "scope",{ + get: function() { + return angular.element("[ui-view]").scope(); } }); - return _list; - } - function _post(url, entities) { - var _list = []; - _list._promise = $http({ - method: 'POST', - url: url, - headers: { - "Content-Type": "application/json" - }, - data: entities - }).success(function(data) { - _list.push.apply(_list, data.obj); - }); - return _list; - } - function _delete(url) { - var _list = []; - _list._promise = $http({ - method: 'DELETE', - url: url, - headers: { - "Content-Type": "application/json" - }, - }).success(function(data) { - _list.push.apply(_list, data.obj); - }); - return _list; - } - function ParseCondition(condition) { - var _this = this; - _this.condition = ""; - _this.additionalCondition = {}; - - if(typeof condition === "string") { - _this.condition = condition; - } else { - _this.condition = $.map(condition, function(value, key) { - if(!key.match(/^_/)) { - if(value === undefined || value === null) { - return '@' + key + '=~".*"'; - } else { - return '@' + key + '="' + value + '"'; - } - } else { - _this.additionalCondition[key] = value; - return null; - } - }).join(" AND "); - } - return _this; - } + // Clean up + $scope.$on('$stateChangeStart', function (event, next, nextParam, current, currentParam) { + console.log("[Switch] current ->", current, currentParam); + console.log("[Switch] next ->", next, nextParam); + // Page initialization + PageConfig.reset(); - var pkg = { - _query: _query, - _post: _post, - - updateEntity: function(serviceName, entities, config) { - config = config || {}; - if(!$.isArray(entities)) entities = [entities]; + // Dynamic navigation list + if(next.pageConfig) { + $scope.PageConfig.navConfig = $injector.get(next.pageConfig); + } else { + $scope.PageConfig.navConfig = {}; + } - // Post clone entities - var _entities = $.map(entities, function(entity) { - var _entity = {}; + // Authorization + // > Login check + if (!common.getValueByPath(next, "access.skipCheck", false)) { + if (!Authorization.isLogin) { + console.log("[Authorization] Need access. Redirect..."); + $wrapState.go("login"); + } + } - // Clone variables - $.each(entity, function(key, value) { - // Skip inner variables - if(!key.match(/^__/)) { - _entity[key] = entity[key]; + // > Role control + /*var _roles = common.getValueByPath(next, "access.roles", []); + if (_roles.length && Authorization.userProfile.roles) { + var _roleMatch = false; + $.each(_roles, function (i, roleName) { + if (Authorization.isRole(roleName)) { + _roleMatch = true; + return false; } }); - // Add timestamp - if(config.timestamp !== false) { - if(config.createTime !== false && !_entity.createdTime) { - _entity.createdTime = new moment().valueOf(); - } - if(config.lastModifiedDate !== false) { - _entity.lastModifiedDate = new moment().valueOf(); - } + if (!_roleMatch) { + $wrapState.path("/dam"); } + }*/ + }); - return _entity; - }); + $scope.$on('$stateChangeError', function (event, next, nextParam, current, currentParam, error) { + console.error("[Switch] Error", arguments); + }); - return _post(app.getURL("updateEntity", {serviceName: serviceName}), _entities); - }, + // Get side bar navigation item class + $scope.getNavClass = function (page) { + var path = page.url.replace(/^#/, ''); - deleteEntity: function(serviceName, entities) { - if(!$.isArray(entities)) entities = [entities]; + if ($wrapState.path() === path) { + PageConfig.pageTitle = PageConfig.pageTitle || page.title; + return "active"; + } else { + return ""; + } + }; - var _entities = $.map(entities, function(entity) { - return typeof entity === "object" ? entity.encodedRowkey : entity; - }); - return _post(app.getURL("deleteEntity", {serviceName: serviceName}), _entities); - }, - deleteEntities: function(serviceName, condition) { - return _delete(app.getURL("deleteEntities", {serviceName: serviceName, condition: new ParseCondition(condition).condition})); - }, - - queryEntity: function(serviceName, encodedRowkey) { - return _query("queryEntity", {serviceName: serviceName, encodedRowkey: encodedRowkey}); - }, - queryEntities: function(serviceName, condition, fields) { - return _query("queryEntities", {serviceName: serviceName, _condition: new ParseCondition(condition), values: fields}); - }, - queryGroup: function(serviceName, condition, groupBy, fields) { - return _query("queryGroup", {serviceName: serviceName, _condition: new ParseCondition(condition), groupBy: groupBy, values: fields}); - }, - querySeries: function(serviceName, condition, groupBy, fields, intervalmin) { - var _cond = new ParseCondition(condition); - var _list = _query("querySeries", {serviceName: serviceName, _condition: _cond, groupBy: groupBy, values: fields, intervalmin: intervalmin}); - _list._promise.success(function() { - if(_list.length === 0) { - _list._empty = true; - _list._convert = true; - - for(var i = 0; i <= (_cond.additionalCondition._endTime.valueOf() - _cond.additionalCondition._startTime.valueOf()) / (1000 * 60 * intervalmin); i += 1) { - _list.push(0); - } - } else if(_list.length === 1) { - _list._convert = true; - var _unit = _list.pop(); - _list.push.apply(_list, _unit.value[0]); - } + // Get side bar navigation item class visible + $scope.getNavVisible = function (page) { + if (!page.roles) return true; - if(_list._convert) { - var _current = _cond.additionalCondition._startTime.clone(); - $.each(_list, function(i, value) { - _list[i] = { - x: _current.valueOf(), - y: value - }; - _current.add(intervalmin, "m"); - }); + for (var i = 0; i < page.roles.length; i += 1) { + var roleName = page.roles[i]; + if (Authorization.isRole(roleName)) { + return true; } - }); - return _list; - }, - - query: function(path, params) { - var _list = []; - _list._promise = $http({ - method: 'GET', - url: app.getURL("query") + path, - params: params - }).success(function(data) { - _list.push.apply(_list, data.obj); - }); - return _list; - }, - - dialog: function(data, callback) { - if(data.success === false || (data.exception || "").trim()) { - return $.dialog({ - title: "OPS", - content: $("
").html(data.exception)
-				}, callback);
 			}
-			return false;
-		},
-	};
-	return pkg;
-});
-
-eagleApp.filter('parseJSON', function() {
-	'use strict';
-
-	return function(input, defaultVal) {
-		return common.parseJSON(input, defaultVal);
-	};
-});
 
-eagleApp.filter('split', function() {
-	'use strict';
-
-	return function(input, regex) {
-		return input.split(regex);
-	};
-});
-
-eagleApp.filter('reverse', function() {
-	'use strict';
-
-	return function(items) {
-		return items.slice().reverse();
-	};
-});
-
-eagleApp.controller('MainCtrl', function($scope, $location, $http, globalContent, Site, Authorization, Entities, nvd3) {
-	'use strict';
-
-	window.globalContent = $scope.globalContent = globalContent;
-	window.site = $scope.site = Site;
-	window.auth = $scope.auth = Authorization;
-	window.entities = $scope.entities = Entities;
-	window.nvd3 = nvd3;
-	$scope.app = app;
-
-	// Clean up
-	$scope.$on('$routeChangeStart', function(event, next, current) {
-		// Page initialization
-		globalContent.pageTitle = "";
-		globalContent.pageSubTitle = "";
-		globalContent.hideSite = false;
-		globalContent.lockSite = false;
-		globalContent.hideSidebar = false;
-		globalContent.hideUser = false;
+			return false;
+		};
 
 		// Authorization
-		// > Login check
-		if(!common.getValueByPath(next, "access.skipCheck", false)) {
-			if(!Authorization.isLogin) {
-				$location.path("/dam/login");
-			}
-		}
-
-		// > Role control
-		var _roles = common.getValueByPath(next, "access.roles", []);
-		if(_roles.length && Authorization.userProfile.roles) {
-			var _roleMatch = false;
-			$.each(_roles, function(i, roleName) {
-				if(Authorization.isRole(roleName)) {
-					_roleMatch = true;
-					return false;
-				}
-			});
-
-			if(!_roleMatch) {
-				$location.path("/dam");
-			}
-		}
+		$scope.logout = function () {
+			console.log("[Authorization] Logout. Redirect...");
+			Authorization.logout();
+			$wrapState.go("login");
+		};
 	});
-
-	// Get side bar navigation item class
-	$scope.getNavClass = function(page) {
-		var path = page.url.replace(/^#/, '');
-
-		if ($location.path() == path) {
-			globalContent.pageTitle = globalContent.pageTitle || page.title;
-			return "active";
-		} else {
-			return "";
-		}
-	};
-
-	// Get side bar navigation item class visible
-	$scope.getNavVisible = function(page) {
-		if(!page.roles) return true;
-
-		for(var i = 0 ; i < page.roles.length ; i += 1) {
-			var roleName = page.roles[i];
-			if(Authorization.isRole(roleName)) {
-				return true;
-			}
-		}
-
-		return false;
-	};
-
-	// Authorization
-	$scope.logout = function() {
-		Authorization.logout();
-		$location.path("/dam/login");
-	};
-});
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/js/app.ui.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/app.ui.js b/eagle-webservice/src/main/webapp/app/public/js/app.ui.js
index 4e0ee6e..28727ba 100644
--- a/eagle-webservice/src/main/webapp/app/public/js/app.ui.js
+++ b/eagle-webservice/src/main/webapp/app/public/js/app.ui.js
@@ -1,66 +1,76 @@
-/*
- * 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() {
-	// ================== AdminLTE Update ==================
-	var _boxSelect = $.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors;
-
-	// Box collapse
-	$(document).on("click", _boxSelect.collapse, function(e) {
-		if(common.getValueByPath($._data(this), "events.click")) return;
-
-		e.preventDefault();
-		$.AdminLTE.boxWidget.collapse($(this));
-	});
-
-	// Box remove
-	$(document).on("click", _boxSelect.remove, function(e) {
-		if(common.getValueByPath($._data(this), "events.click")) return;
-
-		e.preventDefault();
-		$.AdminLTE.boxWidget.remove($(this));
-	});
-
-	// =================== jQuery Update ===================
-	// Slide Toggle
-	var _slideToggle = $.fn.slideToggle;
-	$.fn.slideToggle = function(showOrHide) {
-		if(arguments.length === 1 && typeof showOrHide === "boolean") {
-			if(showOrHide) {
-				this.slideDown();
-			} else {
-				this.slideUp();
-			}
-		} else {
-			_slideToggle.apply(this, arguments);
-		}
-	};
-
-	// Fade Toggle
-	var _fadeToggle = $.fn.fadeToggle;
-	$.fn.fadeToggle = function(showOrHide) {
-		if(arguments.length === 1 && typeof showOrHide === "boolean") {
-			if(showOrHide) {
-				this.fadeIn();
-			} else {
-				this.fadeOut();
-			}
-		} else {
-			_fadeToggle.apply(this, arguments);
-		}
-	};
+/*
+ * 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() {
+	// ================== AdminLTE Update ==================
+	var _boxSelect = $.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors;
+
+	// Box collapse
+	$(document).on("click", _boxSelect.collapse, function(e) {
+		if(common.getValueByPath($._data(this), "events.click")) return;
+
+		e.preventDefault();
+		$.AdminLTE.boxWidget.collapse($(this));
+	});
+
+	// Box remove
+	$(document).on("click", _boxSelect.remove, function(e) {
+		if(common.getValueByPath($._data(this), "events.click")) return;
+
+		e.preventDefault();
+		$.AdminLTE.boxWidget.remove($(this));
+	});
+
+	// =================== jQuery Update ===================
+	// Slide Toggle
+	var _slideToggle = $.fn.slideToggle;
+	$.fn.slideToggle = function(showOrHide) {
+		if(arguments.length === 1 && typeof showOrHide === "boolean") {
+			if(showOrHide) {
+				this.slideDown();
+			} else {
+				this.slideUp();
+			}
+		} else {
+			_slideToggle.apply(this, arguments);
+		}
+	};
+
+	// Fade Toggle
+	var _fadeToggle = $.fn.fadeToggle;
+	$.fn.fadeToggle = function(showOrHide) {
+		if(arguments.length === 1 && typeof showOrHide === "boolean") {
+			if(showOrHide) {
+				this.fadeIn();
+			} else {
+				this.fadeOut();
+			}
+		} else {
+			_fadeToggle.apply(this, arguments);
+		}
+	};
+
+	// Modal
+	var _modal = $.fn.modal;
+	$.fn.modal = function() {
+		setTimeout(function() {
+			$(this).find("input, textarea").filter(':visible:first').focus();
+		}.bind(this), 500);
+		_modal.apply(this, arguments);
+		return this;
+	};
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/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 c5b385f..706eeec 100644
--- a/eagle-webservice/src/main/webapp/app/public/js/common.js
+++ b/eagle-webservice/src/main/webapp/app/public/js/common.js
@@ -1,211 +1,226 @@
-/*
- * 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.
- */
-
-var common = {};
-
-common.template = function (str, list) {
-	$.each(list, function(key, value) {
-		var _regex = new RegExp("\\$\\{" + key + "\\}", "g");
-		str = str.replace(_regex, value);
-	});
-	return str;
-};
-
-common.getValueByPath = function (unit, path, defaultValue) {
-	if(unit === null || unit === undefined) throw "Unit or path can't be empty!";
-	if(path === "" || path === null || path === undefined) return unit;
-
-	path = path.replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "").split(/\./);
-	$.each(path, function(i, path) {
-		unit = unit[path];
-		if(unit === null || unit === undefined) {
-			unit = null;
-			return false;
-		}
-	});
-	if(unit === null && defaultValue !== undefined) {
-		unit = defaultValue;
-	}
-	return unit;
-};
-
-common.setValueByPath = function(unit, path, value) {
-	if(!unit || typeof path !== "string" || path === "") throw "Unit or path can't be empty!";
-
-	var _inArray = false;
-	var _end = 0;
-	var _start = 0;
-	var _unit = unit;
-
-	function _nextPath(array) {
-		var _key = path.slice(_start, _end);
-		if(_inArray) {
-			_key = _key.slice(0, -1);
-		}
-		if(!_unit[_key]) {
-			if(array) {
-				_unit[_key] = [];
-			} else {
-				_unit[_key] = {};
-			}
-		}
-		_unit = _unit[_key];
-	}
-
-	for(; _end < path.length ; _end += 1) {
-		if(path[_end] === ".") {
-			_nextPath(false);
-			_start = _end + 1;
-			_inArray = false;
-		} else if(path[_end] === "[") {
-			_nextPath(true);
-			_start = _end + 1;
-			_inArray = true;
-		}
-	}
-
-	_unit[path.slice(_start, _inArray ? -1 : _end)] = value;
-
-	return unit;
-};
-
-common.parseJSON = function (str, defaultVal) {
-	try {
-		return JSON.parse(str);
-	} catch(err) {
-		if(defaultVal === undefined) {
-			console.warn("Can't parse JSON: " + str);
-		}
-	}
-	return defaultVal === undefined ? null : defaultVal;
-};
-
-common.isEmpty = function(val) {
-	if($.isArray(val)) {
-		return val.length === 0;
-	} else {
-		return val === null || val === undefined;
-	}
-};
-
-// ====================== Format ======================
-common.format = {};
-
-/*
- * Format date to string. Support number, string, Date instance. Will auto convert time zone offset(Moment instance will keep time zone).
- */
-common.format.date = function(val, type) {
-	if(val === undefined || val === null) return "";
-
-	if(typeof val === "number" || typeof val === "string" || val instanceof Date) {
-		val = app.time.offset(val);
-	}
-	switch(type) {
-	default:
-		return val.format("YYYY-MM-DD HH:mm:ss") + (val.utcOffset() === 0 ? '[UTC]' : '');
-	}
-};
-
-// ====================== Array =======================
-common.array = {};
-
-common.array.sum = function(list, path) {
-	var _sum = 0;
-	if(list) {
-		$.each(list, function(i, unit) {
-			var _val = common.getValueByPath(unit, path);
-			if(typeof _val === "number") {
-				_sum += _val;
-			}
-		});
-	}
-	return _sum;
-};
-
-common.array.max = function(list, path) {
-	var _max = null;
-	if(list) {
-		$.each(list, function(i, unit) {
-			var _val = common.getValueByPath(unit, path);
-			if(typeof _val === "number" && (_max === null || _max < _val)) {
-				_max = _val;
-			}
-		});
-	}
-	return _max;
-};
-
-common.array.bottom = function(list, path, count) {
-	var _list = list.slice();
-
-	_list.sort(function(a, b) {
-		var _a = common.getValueByPath(a, path, null);
-		var _b = common.getValueByPath(b, path, null);
-
-		if(_a === _b) return 0;
-		if(_a < _b || _a === null) {
-			return -1;
-		} else {
-			return 1;
-		}
-	});
-	return !count ? _list : _list.slice(0, count);
-};
-common.array.top = function(list, path, count) {
-	var _list = common.array.bottom(list, path);
-	_list.reverse();
-	return !count ? _list : _list.slice(0, count);
-};
-
-common.array.find = function(val, list, path, findAll) {
-	path = path || "";
-	var _list = $.grep(list, function(unit) {
-		return val === common.getValueByPath(unit, path);
-	});
-	return findAll ? _list : (_list.length === 0 ? null : _list[0]);
-};
-
-common.array.filter = function(val, list, path) {
-	return common.array.find(val, list, path, true);
-};
-
-common.array.count = function(list, val, path) {
-	if(arguments.length === 1) {
-		return list.length;
-	} else {
-		return common.array.find(val, list, path, true).length;
-	}
-};
-
-common.array.remove = function(val, list) {
-	for(var i = 0 ; i < list.length ; i += 1) {
-		if(list[i] === val) {
-			list.splice(i, 1);
-			i -= 1;
-		}
-	}
-};
-
-// ======================= Map ========================
-common.map = {};
-
-common.map.toArray = function(map) {
-	return $.map(map, function(unit) {
-		return unit;
-	});
+/*
+ * 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.
+ */
+
+var common = {};
+
+common.template = function (str, list) {
+	$.each(list, function(key, value) {
+		var _regex = new RegExp("\\$\\{" + key + "\\}", "g");
+		str = str.replace(_regex, value);
+	});
+	return str;
+};
+
+common.getValueByPath = function (unit, path, defaultValue) {
+	if(unit === null || unit === undefined) throw "Unit or path can't be empty!";
+	if(path === "" || path === null || path === undefined) return unit;
+
+	path = path.replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "").split(/\./);
+	$.each(path, function(i, path) {
+		unit = unit[path];
+		if(unit === null || unit === undefined) {
+			unit = null;
+			return false;
+		}
+	});
+	if(unit === null && defaultValue !== undefined) {
+		unit = defaultValue;
+	}
+	return unit;
+};
+
+common.setValueByPath = function(unit, path, value) {
+	if(!unit || typeof path !== "string" || path === "") throw "Unit or path can't be empty!";
+
+	var _inArray = false;
+	var _end = 0;
+	var _start = 0;
+	var _unit = unit;
+
+	function _nextPath(array) {
+		var _key = path.slice(_start, _end);
+		if(_inArray) {
+			_key = _key.slice(0, -1);
+		}
+		if(!_unit[_key]) {
+			if(array) {
+				_unit[_key] = [];
+			} else {
+				_unit[_key] = {};
+			}
+		}
+		_unit = _unit[_key];
+	}
+
+	for(; _end < path.length ; _end += 1) {
+		if(path[_end] === ".") {
+			_nextPath(false);
+			_start = _end + 1;
+			_inArray = false;
+		} else if(path[_end] === "[") {
+			_nextPath(true);
+			_start = _end + 1;
+			_inArray = true;
+		}
+	}
+
+	_unit[path.slice(_start, _inArray ? -1 : _end)] = value;
+
+	return unit;
+};
+
+common.parseJSON = function (str, defaultVal) {
+	try {
+		str = (str + "").trim();
+		if(Number(str).toString() === str) throw "Number format";
+		return JSON.parse(str);
+	} catch(err) {
+		if(defaultVal === undefined) {
+			console.warn("Can't parse JSON: " + str);
+		}
+	}
+	return defaultVal === undefined ? null : defaultVal;
+};
+
+common.isEmpty = function(val) {
+	if($.isArray(val)) {
+		return val.length === 0;
+	} else {
+		return val === null || val === undefined;
+	}
+};
+
+// ====================== Format ======================
+common.format = {};
+
+/*
+ * Format date to string. Support number, string, Date instance. Will auto convert time zone offset(Moment instance will keep time zone).
+ */
+common.format.date = function(val, type) {
+	if(val === undefined || val === null) return "";
+
+	if(typeof val === "number" || typeof val === "string" || val instanceof Date) {
+		val = app.time.offset(val);
+	}
+	switch(type) {
+	default:
+		return val.format("YYYY-MM-DD HH:mm:ss") + (val.utcOffset() === 0 ? '[UTC]' : '');
+	}
+};
+
+// ====================== Array =======================
+common.array = {};
+
+common.array.sum = function(list, path) {
+	var _sum = 0;
+	if(list) {
+		$.each(list, function(i, unit) {
+			var _val = common.getValueByPath(unit, path);
+			if(typeof _val === "number") {
+				_sum += _val;
+			}
+		});
+	}
+	return _sum;
+};
+
+common.array.max = function(list, path) {
+	var _max = null;
+	if(list) {
+		$.each(list, function(i, unit) {
+			var _val = common.getValueByPath(unit, path);
+			if(typeof _val === "number" && (_max === null || _max < _val)) {
+				_max = _val;
+			}
+		});
+	}
+	return _max;
+};
+
+common.array.bottom = function(list, path, count) {
+	var _list = list.slice();
+
+	_list.sort(function(a, b) {
+		var _a = common.getValueByPath(a, path, null);
+		var _b = common.getValueByPath(b, path, null);
+
+		if(_a === _b) return 0;
+		if(_a < _b || _a === null) {
+			return -1;
+		} else {
+			return 1;
+		}
+	});
+	return !count ? _list : _list.slice(0, count);
+};
+common.array.top = function(list, path, count) {
+	var _list = common.array.bottom(list, path);
+	_list.reverse();
+	return !count ? _list : _list.slice(0, count);
+};
+
+common.array.find = function(val, list, path, findAll) {
+	path = path || "";
+	var _list = $.grep(list, function(unit) {
+		return val === common.getValueByPath(unit, path);
+	});
+	return findAll ? _list : (_list.length === 0 ? null : _list[0]);
+};
+
+common.array.filter = function(val, list, path) {
+	return common.array.find(val, list, path, true);
+};
+
+common.array.count = function(list, val, path) {
+	if(arguments.length === 1) {
+		return list.length;
+	} else {
+		return common.array.find(val, list, path, true).length;
+	}
+};
+
+common.array.remove = function(val, list) {
+	for(var i = 0 ; i < list.length ; i += 1) {
+		if(list[i] === val) {
+			list.splice(i, 1);
+			i -= 1;
+		}
+	}
+};
+
+common.array.insert = function(val, list, index) {
+	list.splice(index, 0, val);
+};
+
+common.array.moveOffset = function(item, list, offset) {
+	var _index = $.inArray(item, list);
+	var _tgtPos = _index + offset;
+	if(_tgtPos < 0 || _tgtPos >= list.length) return;
+
+	common.array.remove(item, list);
+	common.array.insert(item, list, _index + offset);
+};
+
+// ======================= Map ========================
+common.map = {};
+
+common.map.toArray = function(map) {
+	return $.map(map, function(unit) {
+		return unit;
+	});
 };
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/js/ctrl/alertController.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/ctrl/alertController.js b/eagle-webservice/src/main/webapp/app/public/js/ctrl/alertController.js
deleted file mode 100644
index 2399234..0000000
--- a/eagle-webservice/src/main/webapp/app/public/js/ctrl/alertController.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// =============================================================
-// =                        Alert List                         =
-// =============================================================
-damControllers.controller('alertListCtrl', function(globalContent, Site, damContent, $scope, $routeParams, $interval, $timeout, Entities) {
-	'use strict';
-
-	globalContent.setConfig(damContent.config);
-	globalContent.pageSubTitle = Site.current().name;
-
-	var MAX_PAGESIZE = 10000;
-
-	// Initial load
-	$scope.dataSource = $routeParams.dataSource;
-
-	$scope.alertList = [];
-	$scope.alertList.ready = false;
-
-	// Load data
-	function _loadAlerts() {
-		if($scope.alertList._promise) {
-			$scope.alertList._promise.abort();
-		}
-
-		var _list = Entities.queryEntities("AlertService", {
-			site: Site.current().name,
-			dataSource: $scope.dataSource,
-			hostname: null,
-			_pageSize: MAX_PAGESIZE,
-			_duration: 1000 * 60 * 60 * 24 * 30,
-			__ETD: 1000 * 60 * 60 * 24
-		});
-		$scope.alertList._promise = _list._promise;
-		_list._promise.then(function() {
-			var index;
-
-			if($scope.alertList[0]) {
-				// List new alerts
-				for(index = 0 ; index < _list.length ; index += 1) {
-					var _alert = _list[index];
-					_alert.__new = true;
-					if(_alert.encodedRowkey === $scope.alertList[0].encodedRowkey) {
-						break;
-					}
-				}
-
-				if(index > 0) {
-					$scope.alertList.unshift.apply($scope.alertList, _list.slice(0, index));
-
-					// Clean up UI highlight
-					$timeout(function() {
-						$.each(_list, function(i, alert) {
-							delete alert.__new;
-						});
-					}, 100);
-				}
-			} else {
-				// List all alerts
-				$scope.alertList.push.apply($scope.alertList, _list);
-			}
-
-			$scope.alertList.ready = true;
-		});
-	}
-
-	_loadAlerts();
-	var _loadInterval = $interval(_loadAlerts, app.time.refreshInterval);
-	$scope.$on('$destroy',function(){
-		$interval.cancel(_loadInterval);
-	});
-});
-
-// =============================================================
-// =                       Alert Detail                        =
-// =============================================================
-damControllers.controller('alertDetailCtrl', function(globalContent, Site, damContent, $scope, $routeParams, Entities) {
-	'use strict';
-
-	globalContent.setConfig(damContent.config);
-	globalContent.pageTitle = "Alert Detail";
-	globalContent.navPath = ["Alert List", "Alert Detail"];
-	globalContent.lockSite = true;
-
-	$scope.common = common;
-
-	// Query policy
-	$scope.alertList = Entities.queryEntity("AlertService", $routeParams.encodedRowkey);
-	$scope.alertList._promise.then(function() {
-		if($scope.alertList.length === 0) {
-			$.dialog({
-				title: "OPS!",
-				content: "Alert not found!",
-			}, function() {
-				location.href = "#/dam/alertList";
-			});
-			return;
-		} else {
-			var alert = $scope.alertList[0];
-
-			$scope.alert = alert;
-			Site.current(Site.find($scope.alert.tags.site));
-			console.log($scope.alert);
-		}
-	});
-
-	// UI
-	$scope.getMessageTime = function(alert) {
-		var _time = common.getValueByPath(alert, "alertContext.properties.timestamp");
-		return Number(_time);
-	};
-});

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/d37643b0/eagle-webservice/src/main/webapp/app/public/js/ctrl/authController.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/app/public/js/ctrl/authController.js b/eagle-webservice/src/main/webapp/app/public/js/ctrl/authController.js
index 1131ca5..1b4f602 100644
--- a/eagle-webservice/src/main/webapp/app/public/js/ctrl/authController.js
+++ b/eagle-webservice/src/main/webapp/app/public/js/ctrl/authController.js
@@ -16,48 +16,54 @@
  * limitations under the License.
  */
 
-// =============================================================
-// =                     User Profile List                     =
-// =============================================================
-damControllers.controller('authLoginCtrl', function(globalContent, Site, Authorization, $scope) {
+(function() {
 	'use strict';
 
-	globalContent.hideSidebar = true;
-	globalContent.hideSite = true;
-	globalContent.hideUser = true;
+	var eagleControllers = angular.module('eagleControllers');
+	// =============================================================
+	// =                     User Profile List                     =
+	// =============================================================
+	eagleControllers.controller('authLoginCtrl', function (PageConfig, Site, Authorization, Application, $scope) {
+		PageConfig.hideSidebar = true;
+		PageConfig.hideApplication = true;
+		PageConfig.hideSite = true;
+		PageConfig.hideUser = true;
 
-	$scope.username = "";
-	$scope.password = "";
-	$scope.lock = false;
+		$scope.username = "";
+		$scope.password = "";
+		$scope.lock = false;
 
-	// UI
-	setTimeout(function() {
-		$("#username").focus();
-	});
+		// UI
+		setTimeout(function () {
+			$("#username").focus();
+		});
 
-	// Login
-	$scope.login = function(event, forceSubmit) {
-		if($scope.lock) return;
+		// Login
+		$scope.login = function (event, forceSubmit) {
+			if ($scope.lock) return;
 
-		if(event.which === 13 || forceSubmit) {
-			$scope.lock = true;
+			if (event.which === 13 || forceSubmit) {
+				$scope.lock = true;
 
-			Authorization.login($scope.username, $scope.password).then(function(success) {
-				if(success) {
-					Site.refresh();
-					Authorization.refresh();
-					Authorization.path(true);
-				} else {
-					$.dialog({
-						title: "OPS",
-						content: "User name or password not correct."
-					}).on("hidden.bs.modal", function() {
-						$("#username").focus();
-					});
-				}
-			}).finally(function() {
-				$scope.lock = false;
-			});
-		}
-	};
-});
\ No newline at end of file
+				Authorization.login($scope.username, $scope.password).then(function (success) {
+					if (success) {
+						console.log("[Login] Login success! Reload data...");
+						Authorization.reload().then(function() {}, function() {console.warn("Site error!");});
+						Application.reload().then(function() {}, function() {console.warn("Site error!");});
+						Site.reload().then(function() {}, function() {console.warn("Site error!");});
+						Authorization.path(true);
+					} else {
+						$.dialog({
+							title: "OPS",
+							content: "User name or password not correct."
+						}).on("hidden.bs.modal", function () {
+							$("#username").focus();
+						});
+					}
+				}).finally(function () {
+					$scope.lock = false;
+				});
+			}
+		};
+	});
+})();
\ No newline at end of file