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 2016/09/28 05:38:53 UTC

[12/14] incubator-eagle git commit: [EAGLE-574] UI refactor for support 0.5 api

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/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
new file mode 100644
index 0000000..56850d7
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/index.html
@@ -0,0 +1,250 @@
+<!DOCTYPE html>
+<!--
+  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.
+  -->
+
+<html ng-controller="MainCtrl">
+	<head>
+		<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<meta charset="UTF-8">
+		<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
+		<link rel="shortcut icon" href="public/images/favicon.png">
+
+		<title>Eagle</title>
+		<link rel="shortcut icon" type="image/png" href="public/images/favicon.png">
+
+		<!-- ref:css public/css/doc.css -->
+		<link href="../node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" type="text/css" media="screen">
+		<link href="../node_modules/zombiej-bootstrap-components/bootstrap-components/css/bootstrap-components.css" rel="stylesheet" type="text/css" media="screen">
+
+		<link href="../node_modules/zombiej-nvd3/build/nv.d3.css" rel="stylesheet" type="text/css" />
+
+		<link href="../node_modules/font-awesome/css/font-awesome.css" rel="stylesheet" type="text/css" />
+
+		<link href="../node_modules/admin-lte/dist/css/AdminLTE.css" rel="stylesheet" type="text/css" />
+		<link href="../node_modules/admin-lte/dist/css/skins/skin-blue.css" rel="stylesheet" type="text/css" />
+
+		<link href="public/css/animation.css" rel="stylesheet" type="text/css" media="screen">
+		<link href="public/css/sortTable.css" rel="stylesheet" type="text/css" media="screen">
+		<link href="public/css/main.css" rel="stylesheet" type="text/css" media="screen">
+		<!-- endref -->
+	</head>
+	<body class="skin-blue sidebar-mini" ng-class="{'no-sidebar' : PageConfig.hideSidebar}">
+		<!-- Site wrapper -->
+		<div class="wrapper">
+			<header class="main-header">
+				<a href="#/" class="logo">
+					<span class="logo-mini"><img src="public/images/favicon_white.png" /></span>
+					<span class="logo-lg">Apache Eagle</span>
+				</a>
+				<!-- Header Navbar: style can be found in header.less -->
+				<nav class="navbar navbar-static-top" role="navigation">
+					<!-- Sidebar toggle button-->
+					<a ng-hide="PageConfig.hideSidebar" class="sidebar-toggle" data-toggle="offcanvas" role="button">
+						<span class="sr-only">Toggle navigation</span>
+						<span class="icon-bar"></span>
+						<span class="icon-bar"></span>
+						<span class="icon-bar"></span>
+					</a>
+
+					<div class="navbar-custom-menu">
+						<ul class="nav navbar-nav">
+							<li class="dropdown time-picker" ng-if="Time.pickerType === Time.TIME_RANGE_PICKER">
+								<a data-toggle="dropdown" aria-expanded="false">
+									<i class="fa fa-calendar"></i>
+									{{Time.format("startTime", Time.SHORT_FORMAT)}} ~ {{Time.format("endTime", Time.SHORT_FORMAT)}}
+								</a>
+								<ul class="dropdown-menu">
+									<li><a ng-click="setLastDuration(2)"><i class="fa fa-clock-o"></i>Last 2 Hours</a></li>
+									<li><a ng-click="setLastDuration(6)"><i class="fa fa-clock-o"></i>Last 6 Hours</a></li>
+									<li><a ng-click="setLastDuration(12)"><i class="fa fa-clock-o"></i>Last 12 Hours</a></li>
+									<li><a ng-click="setLastDuration(24)"><i class="fa fa-clock-o"></i>Last 24 Hours</a></li>
+									<li><a ng-click="customizeTimeRange()"><i class="fa fa-clock-o"></i>Customize</a></li>
+								</ul>
+							</li>
+							<li>
+								<a data-toggle="dropdown" aria-expanded="false">
+									<i class="glyphicon glyphicon-question-sign"></i>
+								</a>
+
+								<ul class="dropdown-menu">
+									<li><a>How to start using eagle</a></li>
+									<li><a>How to register new site</a></li>
+									<li><a>How to install application</a></li>
+									<li><a>How to manage application</a></li>
+									<li><a>How to develop application</a></li>
+								</ul>
+							</li>
+						</ul>
+					</div>
+				</nav>
+			</header>
+
+			<!-- =============================================== -->
+			<!-- Left side column. contains the side bar -->
+			<aside class="main-sidebar" ng-hide="PageConfig.hideSidebar">
+				<!-- side bar: style can be found in sidebar.less -->
+				<section class="sidebar">
+					<ul class="sidebar-menu">
+						<li ng-repeat="portal in Portal.list track by $index" ng-class="{treeview: portal.list}">
+							<a ng-href="{{portal.path}}">
+								<i class="fa fa-{{portal.icon || 'circle-o'}}"></i>
+								<span>{{portal.name}}</span>
+								<i class="fa fa-angle-left pull-right" ng-if="portal.list"></i>
+							</a>
+							<ul class="treeview-menu" ng-if="portal.list">
+								<li ng-repeat="subPortal in portal.list track by $index" ng-class="{active: getNavClass(subPortal)}">
+									<a ng-href="{{subPortal.path}}">
+										<i class="fa fa-{{subPortal.icon || 'circle-o'}}"></i>
+										<span>{{subPortal.name}}</span>
+									</a>
+								</li>
+							</ul>
+						</li>
+					</ul>
+				</section>
+				<!-- /.sidebar -->
+			</aside>
+
+			<!-- =============================================== -->
+			<!-- Right side column. Contains the navbar and content of the page -->
+			<div class="content-wrapper">
+				<!-- Content Header (Page header) -->
+				<section class="content-header" ng-hide="PageConfig.hideTitle">
+					<h1>
+						<span class="pageTitle">{{PageConfig.title}}</span>
+						<small class="pageSubTitle">{{PageConfig.subTitle}}</small>
+					</h1>
+
+
+					<ol class="breadcrumb">
+						<li ng-repeat="navPath in PageConfig.navPath">
+							<a ng-href="#{{navPath.path}}">
+								<span class="fa fa-home" ng-if="$first"></span>
+								{{navPath.title || navPath.path}}
+							</a>
+						</li>
+					</ol>
+				</section>
+
+				<!-- Main content -->
+				<section class="content">
+					<div id="content">
+						<div ui-view></div>
+					</div>
+				</section><!-- /.content -->
+			</div><!-- /.content-wrapper -->
+
+			<footer class="main-footer">
+				<div class="pull-right hidden-xs">
+					<b>License</b>
+					<a href="http://www.apache.org/licenses/LICENSE-2.0" class="text-muted">Apache-2.0</a>
+				</div>
+				<strong>
+					Apache Eagle
+					<a target="_blank" href="https://eagle.incubator.apache.org/">Home</a> /
+					<a target="_blank" href="https://eagle.incubator.apache.org/docs/community.html">Community</a> /
+					<a target="_blank" href="https://cwiki.apache.org/confluence/display/EAG/FAQ">FAQ</a>
+				</strong>
+			</footer>
+		</div><!-- ./wrapper -->
+
+		<!-- Modal: Time Range Picker -->
+		<div class="modal fade" tabindex="-1" role="dialog" id="eagleTimeRangeMDL">
+			<div class="modal-dialog" role="document">
+				<div class="modal-content">
+					<div class="modal-header">
+						<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+						<h4 class="modal-title">Customize Time Range</h4>
+					</div>
+					<div class="modal-body">
+						<div class="row">
+							<div class="col-sm-6">
+								<div class="form-group">
+									<label for="eagleStartTime">Start Time</label>
+									<input type="text" class="form-control" data-container="body" data-toggle="datepicker" id="eagleStartTime">
+								</div>
+							</div>
+							<div class="col-sm-6">
+								<div class="form-group">
+									<label for="eagleEndTime">End Time</label>
+									<input type="text" class="form-control" data-container="body" data-toggle="datepicker" id="eagleEndTime" data-position="right">
+								</div>
+							</div>
+						</div>
+					</div>
+					<div class="modal-footer">
+						<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+						<button type="button" class="btn btn-primary" ng-click="updateTimeRange()">Change</button>
+					</div>
+				</div>
+			</div>
+		</div>
+
+		<!-- ref:js public/js/modules.js -->
+		<script src="../node_modules/jquery/dist/jquery.min.js"></script>
+		<script src="../node_modules/jquery-slimscroll/jquery.slimscroll.min.js"></script>
+		<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
+		<script src="../node_modules/zombiej-bootstrap-components/bootstrap-components/js/bootstrap-components.min.js"></script>
+		<script src="../node_modules/moment/min/moment-with-locales.min.js"></script>
+		<script src="../node_modules/moment-timezone/builds/moment-timezone-with-data.min.js"></script>
+		<script src="../node_modules/echarts/dist/echarts.min.js"></script>
+		<script src="../node_modules/admin-lte/dist/js/app.min.js"></script>
+		<script src="../node_modules/angular/angular.min.js"></script>
+		<script src="../node_modules/angular-resource/angular-resource.min.js"></script>
+		<script src="../node_modules/angular-route/angular-route.min.js"></script>
+		<script src="../node_modules/angular-animate/angular-animate.min.js"></script>
+		<script src="../node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js"></script>
+		<script src="../node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
+		<!-- endref -->
+
+		<!-- ref:js public/js/doc.min.js -->
+		<!-- Worker -->
+		<script src="public/js/worker/sortTableFunc.js" type="text/javascript" charset="utf-8"></script>
+
+		<!-- Application -->
+		<script src="public/js/common.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/index.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/app.js" type="text/javascript" charset="utf-8"></script>
+
+		<!-- Service -->
+		<script src="public/js/services/main.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/timeSrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/pageSrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/widgetSrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/wrapStateSrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/entitySrv.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/services/siteSrv.js" type="text/javascript" charset="utf-8"></script>
+		<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>
+
+		<!-- Components -->
+		<script src="public/js/components/main.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/components/sortTable.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/components/chart.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/components/widget.js" type="text/javascript" charset="utf-8"></script>
+
+		<!-- Controllers -->
+		<script src="public/js/ctrls/main.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/ctrls/mainCtrl.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/ctrls/alertCtrl.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/ctrls/integrationCtrl.js" type="text/javascript" charset="utf-8"></script>
+		<script src="public/js/ctrls/siteCtrl.js" type="text/javascript" charset="utf-8"></script>
+		<!-- endref -->
+	</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/alert/list.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/alert/list.html b/eagle-server/src/main/webapp/app/dev/partials/alert/list.html
new file mode 100644
index 0000000..d493976
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/alert/list.html
@@ -0,0 +1,21 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	Good!
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/alert/main.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/alert/main.html b/eagle-server/src/main/webapp/app/dev/partials/alert/main.html
new file mode 100644
index 0000000..2e062a8
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/alert/main.html
@@ -0,0 +1,29 @@
+<!--
+  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.
+  -->
+
+<div class="nav-tabs-custom">
+	<ul class="nav nav-tabs">
+		<li ng-class="{active: getState() === 'alert.list'}"><a href="#/alert/">Explore Triggered Alerts</a></li>
+		<li ng-class="{active: getState() === 'alert.policyList'}"><a href="#/alert/policyList">Manage Policies</a></li>
+		<li ng-class="{active: ['alert.policyCreate', 'alert.policyEdit'].indexOf(getState()) >= 0}"><a href="#/alert/policyCreate">Define Alert Policy</a></li>
+	</ul>
+	<div class="tab-content no-padding">
+		<div ui-view></div>
+	</div>
+</div>
+

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.back.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.back.html b/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.back.html
new file mode 100644
index 0000000..3c335f7
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.back.html
@@ -0,0 +1,108 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<ul class="timeline">
+		<!-- Base Info -->
+		<li class="time-label">
+			<span class="bg-blue">#1. Basic Information</span>
+		</li>
+		<li>
+			<span class="fa fa-file-text bg-aqua"></span>
+			<div class="timeline-item">
+				<div class="timeline-body">
+					<div class="form-group">
+						<label>Policy Name</label>
+						<input type="text" class="form-control" ng-model="policy.name" />
+					</div>
+					<div class="form-group">
+						<label>Severity</label>
+						<select class="form-control" ng-model="policy.severity">
+							<option>WARNING</option>
+							<option>CRITICAL</option>
+							<option>DANGER</option>
+						</select>
+					</div>
+					<div class="form-group">
+						<label>Description</label>
+						<textarea class="form-control" ng-model="policy.description" rows="3"></textarea>
+					</div>
+				</div>
+			</div>
+		</li>
+
+		<!-- Alert Stream -->
+		<li class="time-label">
+			<span class="bg-blue">#2. Alert Stream</span>
+		</li>
+		<li>
+			<span class="fa fa-rocket bg-aqua"></span>
+			<div class="timeline-item">
+				<div class="timeline-body">
+					<div class="form-group">
+						<label>App Integration</label>
+						<select class="form-control"></select>
+					</div>
+					<div class="form-group">
+						<label>Alert Stream</label>
+						<select class="form-control"></select>
+					</div>
+				</div>
+			</div>
+		</li>
+
+		<!-- Streaming Logic -->
+		<li class="time-label">
+			<span class="bg-blue">#3. Streaming Logic</span>
+		</li>
+		<li>
+			<span class="fa fa-trophy bg-aqua"></span>
+			<div class="timeline-item">
+				<div class="timeline-body">
+					<div class="form-group">
+						<label>Policy Type</label>
+						<select class="form-control"></select>
+					</div>
+					<div class="form-group">
+						<label>Policy Logic</label>
+						<textarea class="form-control" rows="5"></textarea>
+					</div>
+				</div>
+			</div>
+		</li>
+
+		<!-- Publication Configuration -->
+		<li class="time-label">
+			<span class="bg-blue">#4. Publication Configuration</span>
+		</li>
+		<li>
+			<span class="fa fa-envelope bg-aqua"></span>
+			<div class="timeline-item">
+				<div class="timeline-body">
+					<div class="form-group">
+						<label>Publication Type</label>
+						<select class="form-control">
+							<option>NOTIFICATION</option>
+						</select>
+					</div>
+					<a>+ New Publication</a>
+				</div>
+			</div>
+		</li>
+	</ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.html b/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.html
new file mode 100644
index 0000000..9a1cbe4
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/alert/policyEdit.html
@@ -0,0 +1,29 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<ul class="stepGuide">
+		<li>
+			<span class="icon bg-green">1</span>
+			<span class="title">This is the title!!!</span>
+		</li>
+		<li>
+			<span class="icon">2</span>
+		</li>
+	</ul>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/alert/policyList.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/alert/policyList.html b/eagle-server/src/main/webapp/app/dev/partials/alert/policyList.html
new file mode 100644
index 0000000..2d4703f
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/alert/policyList.html
@@ -0,0 +1,63 @@
+<!--
+  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.
+  -->
+
+<div class="box box-solid">
+	<div class="box-body">
+		<div sort-table="policyList" ng-show="policyList.length">
+			<table class="table table-bordered">
+				<thead>
+					<tr>
+						<th sortpath="name" width="20%">Name</th>
+						<th sortpath="definition.type" width="70">Type</th>
+						<th>Description</th>
+						<th width="85">Action</th>
+					</tr>
+				</thead>
+				<tbody>
+					<tr>
+						<td>
+							<a ng-href="#/alert/policyEdit/{{item.name}}">{{item.name}}</a>
+						</td>
+						<td class="text-center"><span class="label label-primary">{{item.definition.type}}</span></td>
+						<td>{{item.description}}</td>
+						<td class="text-center">
+							<div class="btn-group btn-group-xs">
+								<button class="btn btn-default"><span class="fa fa-play"></span></button>
+								<button class="btn btn-default"><span class="fa fa-pencil"></span></button>
+								<button class="btn btn-danger" ng-click="deletePolicy(item)"><span class="fa fa-trash"></span></button>
+							</div>
+						</td>
+					</tr>
+				</tbody>
+			</table>
+		</div>
+
+		<div class="callout callout-warning no-margin" ng-show="policyList._done && policyList.length === 0">
+			<h4>No Policy yet</h4>
+			<p>You have not create policy yet. Click <a href="#/alert/policyCreate">here</a> to create a new policy.</p>
+		</div>
+	</div>
+
+	<div class="overlay" ng-if="!policyList._done">
+		<i class="fa fa-refresh fa-spin"></i>
+	</div>
+
+	<div class="box-footer text-right">
+		<a href="#/alert/policyCreate" class="btn btn-primary">New Policy</a>
+	</div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/home.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/home.html b/eagle-server/src/main/webapp/app/dev/partials/home.html
new file mode 100644
index 0000000..ab75b18
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/home.html
@@ -0,0 +1,60 @@
+<!--
+  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.
+  -->
+
+<!--div class="row" ng-repeat="banner in bannerList track by $index">
+	<div class="col-sm-12" ng-if="banner.title">
+		<h3>{{banner.title}}</h3>
+	</div>
+	<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="widget in banner.list track by $index">
+		<div class="small-box {{widget.color || 'bg-aqua'}}">
+			<div class="inner">
+				<h3>{{widget.title || "Untitled"}}</h3>
+				<p>{{widget.description || "-"}}</p>
+				<p>{{widget.additionalTips || "&nbsp;"}}</p>
+			</div>
+			<div class="icon">
+				<i class="fa fa-question-circle"></i>
+			</div>
+			<a class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
+		</div>
+	</div>
+</div-->
+<div class="row flex">
+	<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="widget in Widget.list track by $index">
+		<div widget="widget"></div>
+	</div>
+</div>
+
+<!--div class="row flex">
+	<div class="col-md-4">
+		<div style="background: red; height: 200px;">111</div>
+	</div>
+	<div class="col-md-4">
+		<div style="background: green;">222</div>
+		<div style="background: blue;">222</div>
+	</div>
+	<div class="col-md-4">
+		<div style="background: red;">333</div>
+	</div>
+	<div class="col-md-4">
+		<div style="background: green;">444</div>
+	</div>
+	<div class="col-md-4">
+		<div style="background: red;">555</div>
+	</div>
+</div-->

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/integration/applicationList.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/integration/applicationList.html b/eagle-server/src/main/webapp/app/dev/partials/integration/applicationList.html
new file mode 100644
index 0000000..bc603a7
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/integration/applicationList.html
@@ -0,0 +1,80 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<table class="table table-bordered table-striped">
+		<thead>
+		<tr>
+			<th>Application</th>
+			<th>Type</th>
+			<th>Version</th>
+			<th>Path</th>
+			<th>Streams</th>
+			<th>Description</th>
+		</tr>
+		</thead>
+		<tbody>
+			<tr ng-repeat="app in Application.providerList track by $index">
+				<td class="text-no-break"><a ng-click="showAppDetail(app)">{{app.name}}</a></td>
+				<td>{{app.type}}</td>
+				<td class="text-no-break">{{app.version}}</td>
+				<td>{{app.viewPath}}</td>
+				<td>
+					<ul>
+						<li ng-repeat="stream in app.streams track by $index">
+							{{stream.streamId}}
+						</li>
+					</ul>
+				</td>
+				<td>{{app.description}}</td>
+			</tr>
+		</tbody>
+	</table>
+</div>
+
+
+<!-- Modal: Application information -->
+<div class="modal fade" role="dialog" id="appMDL">
+	<div class="modal-dialog modal-lg">
+		<div class="modal-content">
+			<div class="modal-header">
+				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+					<span aria-hidden="true">�</span>
+				</button>
+				<h4 class="modal-title" id="myModalLabel">{{application.name}}</h4>
+			</div>
+			<div class="modal-body">
+				<ul class="nav nav-tabs">
+					<li class="active"><a href="[data-id='install']" data-toggle="tab">Install</a></li>
+					<li><a href="[data-id='uninstall']" data-toggle="tab">Uninstall</a></li>
+				</ul>
+				<div class="tab-content">
+					<div class="tab-pane active" data-id="install">
+						<pre ng-bind-html="installHTML"></pre>
+					</div>
+					<div class="tab-pane" data-id="uninstall">
+						<pre ng-bind-html="uninstallHTML"></pre>
+					</div>
+				</div>
+			</div>
+			<div class="modal-footer">
+				<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+			</div>
+		</div>
+	</div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/integration/main.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/integration/main.html b/eagle-server/src/main/webapp/app/dev/partials/integration/main.html
new file mode 100644
index 0000000..daea22e
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/integration/main.html
@@ -0,0 +1,29 @@
+<!--
+  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.
+  -->
+
+<div class="nav-tabs-custom">
+	<ul class="nav nav-tabs">
+		<li ng-class="{active: getState().indexOf('integration.site') !== -1}"><a href="#/integration/siteList">Sites</a></li>
+		<li ng-class="{active: getState() === 'integration.applicationList'}"><a href="#/integration/applicationList">Applications</a></li>
+		<li ng-class="{active: getState() === 'integration.streamList'}"><a href="#/integration/streamList">Streams</a></li>
+	</ul>
+	<div class="tab-content no-padding">
+		<div ui-view></div>
+	</div>
+</div>
+

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/integration/site.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/integration/site.html b/eagle-server/src/main/webapp/app/dev/partials/integration/site.html
new file mode 100644
index 0000000..b391b49
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/integration/site.html
@@ -0,0 +1,95 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<p class="text-danger" ng-if="site.applicationList.length === 0">
+		<span class="fa fa-exclamation-triangle"></span> Site must install at least one application to start up.
+	</p>
+	<p class="text-warning" ng-if="site.applicationList.length !== 0 && getStartedAppCount() === 0">
+		<span class="fa fa-exclamation-triangle"></span> No application started.
+	</p>
+
+	<table class="table table-bordered table-hover">
+		<thead>
+			<tr>
+				<th>App</th>
+				<th width="10">Status</th>
+				<th>Version</th>
+				<th>Description</th>
+				<!--th>Quick Links</th-->
+				<th width="150">Actions</th>
+			</tr>
+		</thead>
+		<tbody>
+			<tr ng-repeat="app in applicationList track by $index">
+				<td><a ng-click="showAppDetail(app)">{{app.origin.name}}</a></td>
+				<td class="text-center">
+					<span class="label label-{{getAppStatusClass(app)}}" ng-if="app.installed">{{app.status}}</span>
+					<span class="label label-default" ng-if="!app.installed">UNINSTALLED</span>
+				</td>
+				<td>{{app.origin.version}}</td>
+				<td>{{app.description}}</td>
+				<!--td>TODO: ui link</td-->
+				<td class="text-center">
+					<div class="btn-group btn-group-xs" ng-if="app.installed">
+						<!--button class="btn btn-default btn-sm">Monitor</button-->
+						<button class="btn btn-default btn-sm" ng-click="startApp(app)">Start</button>
+						<button class="btn btn-default btn-sm" ng-click="stopApp(app)">Stop</button>
+						<button class="btn btn-default btn-sm" ng-click="uninstallApp(app)">Uninstall</button>
+					</div>
+					<div class="btn-group btn-group-xs" ng-if="!app.installed">
+						<button class="btn btn-primary btn-sm" ng-click="installApp(app)">Install Application</button>
+					</div>
+				</td>
+			</tr>
+		</tbody>
+	</table>
+</div>
+
+
+
+<!-- Modal: Application information -->
+<div class="modal fade" role="dialog" id="appMDL">
+	<div class="modal-dialog modal-lg">
+		<div class="modal-content">
+			<div class="modal-header">
+				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+					<span aria-hidden="true">�</span>
+				</button>
+				<h4 class="modal-title" id="myModalLabel">{{application.name}}</h4>
+			</div>
+			<div class="modal-body">
+				<ul class="nav nav-tabs">
+					<li class="active"><a href="[data-id='install']" data-toggle="tab">Install</a></li>
+					<li><a href="[data-id='uninstall']" data-toggle="tab">Uninstall</a></li>
+				</ul>
+				<div class="tab-content">
+					<div class="tab-pane active" data-id="install">
+						<pre ng-bind-html="installHTML"></pre>
+					</div>
+					<div class="tab-pane" data-id="uninstall">
+						<pre ng-bind-html="uninstallHTML"></pre>
+					</div>
+				</div>
+			</div>
+			<div class="modal-footer">
+				<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+			</div>
+		</div>
+	</div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/integration/siteList.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/integration/siteList.html b/eagle-server/src/main/webapp/app/dev/partials/integration/siteList.html
new file mode 100644
index 0000000..491d902
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/integration/siteList.html
@@ -0,0 +1,60 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<table class="table table-bordered table-hover">
+		<thead>
+		<tr>
+			<th>Site</th>
+			<th>Description</th>
+			<th>Enabled Apps</th>
+			<th width="95">Actions</th>
+		</tr>
+		</thead>
+		<tbody>
+			<tr ng-repeat="site in Site.list track by $index">
+				<td>
+					<a ui-sref="integration.site({id: site.siteId})">
+						{{site.siteId}}
+						<span ng-if="site.siteName">({{site.siteName}})</span>
+					</a>
+				</td>
+				<td>{{site.description}}</td>
+				<td>
+					<span class="text-muted" ng-if="site.applicationList.length === 0">(Nothing installed...)</span>
+					<ul class="list-inline no-margin">
+						<li ng-repeat="app in site.applicationList track by $index">
+							<span class="label label-primary">
+								{{app.descriptor.name}}
+							</span>
+						</li>
+					</ul>
+				</td>
+				<td class="text-center">
+					<div class="btn-group btn-group-xs">
+						<a class="btn btn-default btn-sm" ui-sref="integration.site({id: site.siteId})">Edit</a>
+						<button class="btn btn-default btn-sm" ng-click="deleteSite(site)">Delete</button>
+					</div>
+				</td>
+			</tr>
+		</tbody>
+	</table>
+</div>
+<div class="box-footer text-right">
+	<button class="btn btn-primary" ng-click="newSite()">New Site</button>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/integration/streamList.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/integration/streamList.html b/eagle-server/src/main/webapp/app/dev/partials/integration/streamList.html
new file mode 100644
index 0000000..beaf743
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/integration/streamList.html
@@ -0,0 +1,52 @@
+<!--
+  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.
+  -->
+
+<div class="box-body">
+	<div sort-table="streamList">
+		<table class="table table-bordered table-hover">
+			<thead>
+				<tr>
+					<th>Stream</th>
+					<th>Provider (App)</th>
+					<th>Site</th>
+					<th>Schema</th>
+					<th width="10">Actions</th>
+				</tr>
+			</thead>
+			<tbody>
+				<tr>
+					<td><span class="label label-primary">{{item.streamId}}</span></td>
+					<td>{{item.appType}}</td>
+					<td>{{item.siteId}}</td>
+					<td>
+						<ul class="no-margin">
+							<li ng-repeat="column in item.schema.columns track by $index">
+								<strong>{{column.name}}</strong>:
+								{{column.type}}
+							</li>
+						</ul>
+					</td>
+					<td>
+						<!-- TODO:link with alert -->
+						<button class="btn btn-primary btn-sm">New Alert</button>
+					</td>
+				</tr>
+			</tbody>
+		</table>
+	</div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/partials/setup.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/partials/setup.html b/eagle-server/src/main/webapp/app/dev/partials/setup.html
new file mode 100644
index 0000000..64944fb
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/partials/setup.html
@@ -0,0 +1,46 @@
+<!--
+  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.
+  -->
+
+<h2>Welcome for using Apache Eagle!</h2>
+<p class="lead">
+	As the first installation, please create a <code>SITE</code>.
+	(A site is a cluster/service which you want to monitor, as a quick start, you could use <code>sandbox</code> by default)
+</p>
+
+<div class="box box-primary">
+	<div class="box-header with-border">
+		<h3 class="box-title">Create new site</h3>
+	</div>
+	<div class="box-body">
+		<div class="form-group">
+			<label>* Site Id</label>
+			<input class="form-control" placeholder="Site id should be unique" ng-model="siteId">
+		</div>
+		<div class="form-group">
+			<label>Display Name</label>
+			<input class="form-control" placeholder="Site display name in UI" ng-model="siteName">
+		</div>
+		<div class="form-group">
+			<label>Description</label>
+			<textarea class="form-control" placeholder="Description about current site" ng-model="description" rows="5"></textarea>
+		</div>
+	</div>
+	<div class="box-footer text-right">
+		<button class="btn btn-primary" ng-click="createSite()" ng-disabled="site === '' || lock">Next</button>
+	</div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/css/animation.css
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/css/animation.css b/eagle-server/src/main/webapp/app/dev/public/css/animation.css
new file mode 100644
index 0000000..cbf4973
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/css/animation.css
@@ -0,0 +1,47 @@
+@CHARSET "UTF-8";
+/*
+ * 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.
+ */
+
+#content > [ui-view].ng-enter,
+#content > [ui-view].ng-leave {
+	position: absolute;
+	left: 0;
+	right: 0;
+	-webkit-transition: all .5s ease-in-out;
+	-moz-transition: all .5s ease-in-out;
+	-o-transition: all .5s ease-in-out;
+	transition: all .3s ease-in-out;
+}
+
+#content > [ui-view].ng-enter {
+	opacity: 0;
+}
+
+#content > [ui-view].ng-enter-active {
+	opacity: 1;
+}
+
+#content > [ui-view].ng-leave {
+	opacity: 1;
+	transform:translate3d(0, 0, 0);
+}
+
+#content > [ui-view].ng-leave-active {
+	opacity: 0;
+	transform:translate3d(20%, 0, 0);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/css/main.css
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/css/main.css b/eagle-server/src/main/webapp/app/dev/public/css/main.css
new file mode 100644
index 0000000..83f9b14
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/css/main.css
@@ -0,0 +1,317 @@
+@CHARSET "UTF-8";
+/*
+ * 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.
+ */
+
+a {
+	cursor: pointer;
+}
+
+/* ========================================================================
+ * =                               Side Bar                               =
+ * ======================================================================== */
+.sidebar-mini.sidebar-collapse .main-header .logo > .logo-mini > img {
+	max-height: 30px;
+}
+
+.main-sidebar .customize-panel {
+	padding: 10px;
+}
+
+.sidebar-collapse .main-sidebar .customize-panel {
+	display: none;
+}
+
+.main-sidebar .customize-panel .btn-group,
+.main-sidebar .customize-panel .btn-group button,
+.main-sidebar .customize-panel .btn-group .dropdown-menu {
+	width: 100%;
+}
+
+.main-sidebar .customize-panel .btn-group button {
+	padding: 5px;
+	background: #374850;
+	border: none;
+	overflow-x: hidden;
+}
+.main-sidebar .customize-panel .btn-group.open button{
+	background: #455b63;
+}
+
+.main-sidebar .customize-panel .btn-group button .caret {
+	position: absolute;
+	right: 10px;
+	top: 13px;
+}
+
+/* ========================================================================
+ * =                                 Main                                 =
+ * ======================================================================== */
+#content {
+	position: relative;
+}
+
+/* ========================================================================
+ * =                                 Grid                                 =
+ * ======================================================================== */
+
+@media (min-width: 1200px) {
+	.row.flex {
+		display: -webkit-box;
+		display: -webkit-flex;
+		display: -ms-flexbox;
+		display: flex;
+		flex-wrap: wrap;
+	}
+
+	.row.flex > [class*='col-'] {
+		display: -webkit-box;
+		display: -webkit-flex;
+		display: -ms-flexbox;
+		display: flex;
+		flex-direction: column;
+		flex-wrap: nowrap;
+	}
+
+	.row.flex > [class*='col-'] > * {
+		flex: auto;
+	}
+}
+
+.row.border-split > div {
+	border: 1px solid #f4f4f4;
+}
+
+.no-padding > .row.border-split {
+	margin-left: 0;
+	margin-right: 0;
+}
+
+/* ========================================================================
+ * =                                Table                                 =
+ * ======================================================================== */
+table .info-wrapper .info-detail {
+	display: none;
+}
+
+table .info-wrapper:hover .info-detail {
+	display: table-row;
+}
+
+table ul {
+	padding: 0 0 0 20px;
+}
+
+table.table pre {
+	white-space: pre-wrap;
+	margin: 0;
+}
+
+table.table pre.inline {
+	padding: 0;
+	border: 0;
+	border-radius: 0;
+	background: transparent;
+}
+
+table.table.table-sm th,
+table.table.table-sm td {
+	padding: 3px 5px;
+	line-height: 120%;
+}
+
+/* ========================================================================
+ * =                              Step Guide                              =
+ * ======================================================================== */
+ul.stepGuide {
+	padding: 0;
+	position: relative;
+	display: inline-block;
+}
+ul.stepGuide:before {
+	display: block;
+	height: 6px;
+	background: #f4f4f4;
+	content: "";
+	position: absolute;
+	top: 12px;
+	left: 5px;
+	right: 5px;
+}
+
+ul.stepGuide li {
+	position: relative;
+	display: inline-block;
+	vertical-align: top;
+	text-align: center;
+}
+ul.stepGuide li:not(:first-child) {
+	margin-left: 15px;
+}
+
+ul.stepGuide li > .icon {
+	display: inline-block;
+	width: 30px;
+	height: 30px;
+	line-height: 30px;
+	text-align: center;
+	background: #f4f4f4;
+	border-radius: 100%;
+}
+
+ul.stepGuide li > .title {
+	display: block;
+}
+
+/* ========================================================================
+ * =                                 Box                                  =
+ * ======================================================================== */
+.box .box-title .label {
+	font-size: 12px;
+	padding: 1px 7px;
+}
+
+.small-box {
+	position: relative;
+	padding-bottom: 30px;
+}
+
+.small-box > .inner a {
+	color: #FFFFFF;
+}
+
+.small-box > .inner a:hover {
+	text-decoration: underline;
+}
+
+.small-box > .small-box-footer {
+	position: absolute;
+	left: 0;
+	right: 0;
+	bottom: 0;
+}
+
+	/* ========================================================================
+     * =                                 Tab                                  =
+     * ======================================================================== */
+.tab-content.keepContent > .tab-pane {
+	display: block;
+}
+
+.tab-content.keepContent > .tab-pane:not(.active) {
+	max-height: 0;
+	overflow: hidden;
+}
+
+/* ========================================================================
+ * =                                Modal                                 =
+ * ======================================================================== */
+.modal .nav-tabs li {
+	border-top: 3px solid transparent;
+}
+
+.modal .nav-tabs li.active {
+	border-top-color: #3c8dbc;
+}
+
+.modal .nav-tabs li a {
+	padding: 8px 15px;
+	border-radius: 0;
+	margin: 0;
+}
+
+.modal .nav-tabs li a,
+.modal .nav-tabs li.active a,
+.modal .nav-tabs li:hover a {
+	border-top: 0;
+}
+
+.modal .tab-content {
+	padding-top: 10px;
+}
+
+/* ========================================================================
+ * =                               Call out                               =
+ * ======================================================================== */
+.callout p,
+.callout span {
+	color: #FFF;
+}
+
+/* ========================================================================
+ * =                                 list                                 =
+ * ======================================================================== */
+.list-inline > li > .label {
+	margin-bottom: 2px;
+	display: inline-block;
+}
+
+/* ========================================================================
+ * =                                 label                                =
+ * ======================================================================== */
+.label.label-sm {
+	padding: .1em .4em .2em;
+}
+
+/* ========================================================================
+ * =                               Timeline                               =
+ * ======================================================================== */
+.nav-tabs-custom .timeline li .timeline-item {
+	background: #f4f4f4;
+}
+
+/* ========================================================================
+ * =                                Widget                                =
+ * ======================================================================== */
+@media (min-width: 1200px) {
+	.row.flex div[widget] {
+		height: 100%;
+	}
+}
+
+/* ========================================================================
+ * =                                 Misc                                 =
+ * ======================================================================== */
+.ng-hide.ng-hide-animate.no-animate {
+	-webkit-transition: none !important;
+	transition: none !important;
+}
+
+.ng-hide.ng-hide-animate.no-animate {
+	display: none;
+}
+
+.text-break {
+	word-break:break-all;
+}
+
+.text-no-break {
+	white-space: nowrap;
+}
+
+.no-select {
+	-webkit-touch-callout: none;
+	-webkit-user-select: none;
+	-khtml-user-select: none;
+	-moz-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+}
+
+.bsc-datepicker {
+	z-index: 2000;
+}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/css/sortTable.css
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/css/sortTable.css b/eagle-server/src/main/webapp/app/dev/public/css/sortTable.css
new file mode 100644
index 0000000..529eb1a
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/css/sortTable.css
@@ -0,0 +1,61 @@
+@CHARSET "UTF-8";
+/*
+ * 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.
+ */
+
+[sort-table] .tool-container .search-box {
+	margin: 0 0 10px 0;
+	position: relative;
+	max-width: 250px;
+	float: left;
+}
+
+[sort-table] .tool-container .search-box input {
+	padding-left: 28px;
+}
+
+[sort-table] .tool-container .search-box .fa-search {
+	pointer-events:none;
+	position: absolute;
+	top: 8px;
+	left: 8px;
+	opacity: 0.5;
+}
+
+[sort-table] .tool-container .page-size {
+	float: right;
+}
+
+[sort-table] .tool-container .page-size select {
+	width: initial;
+	display: inline-block;
+	margin: 0 7px;
+	height: 26px;
+	padding: 0 5px;
+}
+
+[sort-table] .fa.sort-mark {
+	float: right;
+	margin-top: 3px;
+	pointer-events: none;
+	color: #AAA;
+}
+
+[sort-table] .navigation-bar .pagination {
+	float: right;
+	margin-top: 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/images/favicon.png
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/images/favicon.png b/eagle-server/src/main/webapp/app/dev/public/images/favicon.png
new file mode 100644
index 0000000..3bede2a
Binary files /dev/null and b/eagle-server/src/main/webapp/app/dev/public/images/favicon.png differ

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/images/favicon_white.png
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/images/favicon_white.png b/eagle-server/src/main/webapp/app/dev/public/images/favicon_white.png
new file mode 100644
index 0000000..9879e92
Binary files /dev/null and b/eagle-server/src/main/webapp/app/dev/public/images/favicon_white.png differ

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/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
new file mode 100644
index 0000000..4ec77d9
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/app.js
@@ -0,0 +1,311 @@
+/*
+ * 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 app = {};
+
+(function() {
+	'use strict';
+
+	$(document).on("APPLICATION_READY", function (event, register) {
+		console.info("[Eagle] Angular bootstrap...");
+
+		var STATE_NAME_MATCH = /^[^.]*/;
+		var state_next;
+		var state_current;
+		var param_next;
+		var param_current;
+
+		// ======================================================================================
+		// =                                   Initialization                                   =
+		// ======================================================================================
+		var eagleApp = angular.module('eagleApp', ['ngRoute', 'ngAnimate', 'ui.router', 'eagleControllers', 'eagle.service'].concat(register.appList));
+
+		// ======================================================================================
+		// =                                   Router config                                    =
+		// ======================================================================================
+		function routeResolve(config) {
+			var resolve = {};
+			if(config === false) return resolve;
+
+			config = $.extend({
+				auth: true,
+				site: true,
+				application: true
+			}, config);
+
+			if(config.auth) {
+				// TODO: need auth module
+			}
+
+			resolve.Site = function (Site) {
+				return Site.getPromise(config);
+			};
+
+			resolve.Application = function (Application) {
+				return Application.getPromise();
+			};
+
+			resolve.Time = function (Time) {
+				return Time.getPromise(config, state_next, param_next);
+			};
+
+			return resolve;
+		}
+
+		eagleApp.config(function ($stateProvider, $urlRouterProvider, $httpProvider, $animateProvider) {
+			$urlRouterProvider.otherwise("/");
+			$stateProvider
+			// ================================== Home ==================================
+				.state('home', {
+					url: "/",
+					templateUrl: "partials/home.html?_=" + window._TRS(),
+					controller: "homeCtrl",
+					resolve: routeResolve()
+				})
+				.state('setup', {
+					url: "/setup",
+					templateUrl: "partials/setup.html?_=" + window._TRS(),
+					controller: "setupCtrl",
+					resolve: routeResolve({ site: false, application: false })
+				})
+				// ================================= Alerts =================================
+				.state('alert', {
+					abstract: true,
+					url: "/alert/",
+					templateUrl: "partials/alert/main.html?_=" + window._TRS(),
+					controller: "alertCtrl",
+					resolve: routeResolve(false)
+				})
+				.state('alert.list', {
+					url: "",
+					templateUrl: "partials/alert/list.html?_=" + window._TRS(),
+					controller: "alertListCtrl",
+					resolve: routeResolve()
+				})
+				.state('alert.policyList', {
+					url: "policyList",
+					templateUrl: "partials/alert/policyList.html?_=" + window._TRS(),
+					controller: "policyListCtrl",
+					resolve: routeResolve()
+				})
+				.state('alert.policyCreate', {
+					url: "policyCreate",
+					templateUrl: "partials/alert/policyEdit.html?_=" + window._TRS(),
+					controller: "policyCreateCtrl",
+					resolve: routeResolve()
+				})
+				.state('alert.policyEdit', {
+					url: "policyEdit/{name}",
+					templateUrl: "partials/alert/policyEdit.html?_=" + window._TRS(),
+					controller: "policyEditCtrl",
+					resolve: routeResolve()
+				})
+				// =============================== Integration ==============================
+				.state('integration', {
+					abstract: true,
+					url: "/integration/",
+					templateUrl: "partials/integration/main.html?_=" + window._TRS(),
+					controller: "integrationCtrl",
+					resolve: routeResolve(false)
+				})
+				.state('integration.siteList', {
+					url: "siteList",
+					templateUrl: "partials/integration/siteList.html?_=" + window._TRS(),
+					controller: "integrationSiteListCtrl",
+					resolve: routeResolve({ application: false })
+				})
+				.state('integration.site', {
+					url: "site/:id",
+					templateUrl: "partials/integration/site.html?_=" + window._TRS(),
+					controller: "integrationSiteCtrl",
+					resolve: routeResolve({ application: false })
+				})
+				.state('integration.applicationList', {
+					url: "applicationList",
+					templateUrl: "partials/integration/applicationList.html?_=" + window._TRS(),
+					controller: "integrationApplicationListCtrl",
+					resolve: routeResolve({ application: false })
+				})
+				.state('integration.streamList', {
+					url: "streamList",
+					templateUrl: "partials/integration/streamList.html?_=" + window._TRS(),
+					controller: "integrationStreamListCtrl",
+					resolve: routeResolve()
+				})
+				// ================================== Site ==================================
+				.state('site', {
+					url: "/site/:siteId",
+					templateUrl: "partials/home.html?_=" + window._TRS(),
+					controller: "siteCtrl",
+					resolve: routeResolve()
+				})
+			;
+
+			// =========================== Application States ===========================
+			$.each(register.routeList, function (i, route) {
+				var config = $.extend({}, route.config);
+
+				var resolve = {};
+				var resolveConfig = {};
+				if(route.config.resolve) {
+					$.each(route.config.resolve, function (key, value) {
+						if (typeof value === "function") {
+							resolve[key] = value;
+						} else {
+							resolveConfig[key] = value;
+						}
+					});
+				}
+				config.resolve = $.extend(routeResolve(resolveConfig), resolve);
+
+				$stateProvider.state(route.state, config);
+			});
+
+			$httpProvider.interceptors.push(function($q) {
+				function eagleRequestHandle(res) {
+					var data = res.data || {
+						exception: "",
+						message: ""
+					};
+					if(res.status === -1) {
+						$.dialog({
+							title: "AJAX Failed",
+							content: $("<pre>")
+								.text("url:\n" + common.getValueByPath(res, ["config", "url"]))
+						});
+					} else if(data.success === false || res.status === 404) {
+						$.dialog({
+							title: "AJAX Error",
+							content: $("<pre>")
+								.text(
+									"url:\n" + common.getValueByPath(res, ["config", "url"]) + "\n\n" +
+									"status:\n" + res.status + "\n\n" +
+									"exception:\n" + data.exception + "\n\n" +
+									"message:\n" + data.message
+								)
+						});
+					}
+					return res;
+				}
+
+				return {
+					response: eagleRequestHandle,
+					responseError: function(res) {
+						return $q.reject(eagleRequestHandle(res));
+					}
+				};
+			});
+		});
+
+		// ======================================================================================
+		// =                                   Main Controller                                  =
+		// ======================================================================================
+		eagleApp.controller('MainCtrl', function ($scope, $wrapState, $urlRouter, PageConfig, Portal, Widget, Entity, Site, Application, UI, Time) {
+			window._WrapState = $scope.$wrapState = $wrapState;
+			window._PageConfig = $scope.PageConfig = PageConfig;
+			window._Portal = $scope.Portal = Portal;
+			window._Widget = $scope.Widget = Widget;
+			window._Entity = $scope.Entity = Entity;
+			window._Site = $scope.Site = Site;
+			window._Application = $scope.Application = Application;
+			window._UI = $scope.UI = UI;
+			window._Time = $scope.Time = Time;
+			$scope.common = common;
+
+			Object.defineProperty(window, "scope", {
+				get: function () {
+					return angular.element("#content .ng-scope").scope();
+				}
+			});
+
+			// ============================== Route Update ==============================
+			$scope.$on('$stateChangeStart', function (event, next, nextParam, current, currentParam) {
+				console.log("[Switch] current ->", current, currentParam);
+				console.log("[Switch] next ->", next, nextParam);
+
+				state_next = next || {};
+				state_current = current || {};
+				param_next = nextParam;
+				param_current = currentParam;
+
+				var currentName = (current || {}).name || "";
+				var nextName = (next || {}).name || "";
+
+				// Page initialization
+				if(currentName.match(STATE_NAME_MATCH)[0] !== nextName.match(STATE_NAME_MATCH)[0]) {
+					PageConfig.reset();
+				}
+			});
+
+			// ================================ Function ================================
+			// Get side bar navigation item class
+			$scope.getNavClass = function (portal) {
+				var path = (portal.path || "").replace(/^#/, '');
+
+				if ($wrapState.path() === path) {
+					return "active";
+				} else {
+					return "";
+				}
+			};
+
+			// Customize time range
+			$scope.customizeTimeRange = function () {
+				$("#eagleStartTime").val(Time.format("startTime"));
+				$("#eagleEndTime").val(Time.format("endTime"));
+				$("#eagleTimeRangeMDL").modal();
+			};
+
+			$scope.setLastDuration = function (hours) {
+				var endTime = new Time();
+				var startTime = endTime.clone().subtract(hours, "hours");
+				Time.timeRange(startTime, endTime);
+			};
+
+			$scope.updateTimeRange = function () {
+				var startTime = Time.verifyTime($("#eagleStartTime").val());
+				var endTime = Time.verifyTime($("#eagleEndTime").val());
+				if(startTime && endTime) {
+					Time.timeRange(startTime, endTime);
+					$("#eagleTimeRangeMDL").modal("hide");
+				} else {
+					alert("Time range not validate");
+				}
+			};
+
+			// ================================== Init ==================================
+			$.each(register.portalList, function (i, config) {
+				Portal.register(config.portal, config.isSite);
+			});
+
+			$.each(register.widgetList, function (i, config) {
+				Widget.register(config.widget, config.isSite);
+			});
+		});
+
+		// ======================================================================================
+		// =                                      Bootstrap                                     =
+		// ======================================================================================
+		//noinspection JSCheckFunctionSignatures
+		angular.element(document).ready(function() {
+			console.info("[Eagle] UI start...");
+			//noinspection JSCheckFunctionSignatures
+			angular.bootstrap(document, ['eagleApp']);
+		});
+	});
+})();

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/js/common.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/common.js b/eagle-server/src/main/webapp/app/dev/public/js/common.js
new file mode 100644
index 0000000..9f5c4b1
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/common.js
@@ -0,0 +1,387 @@
+/*
+ * 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 scope = {};
+	if(typeof window != 'undefined') {
+		scope = window;
+	} else if(typeof self != 'undefined') {
+		scope = self;
+	}
+	var common = scope.common = {};
+
+	// ============================ 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 can't be empty!";
+		if(path === "" || path === null || path === undefined) return unit;
+
+		if(typeof path === "string") {
+			path = path.replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "").split(/\./);
+		}
+		for(var i = 0 ; i < path.length ; i += 1) {
+			unit = unit[path[i]];
+			if(unit === null || unit === undefined) {
+				unit = null;
+				break;
+			}
+		}
+		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.stringify = function(json) {
+		return JSON.stringify(json, function(key, value) {
+			if(/^(_|\$)/.test(key)) return undefined;
+			return value;
+		});
+	};
+
+	common.isEmpty = function(val) {
+		if($.isArray(val)) {
+			return val.length === 0;
+		} else {
+			return val === null || val === undefined;
+		}
+	};
+
+	common.extend = function(target, origin) {
+		$.each(origin, function(key, value) {
+			if(/^(_|\$)/.test(key)) return;
+
+			target[key] = value;
+		});
+		return target;
+	};
+
+	function merge(obj1, obj2) {
+		$.each(obj2, function (key, value) {
+			var oriValue = obj1[key];
+
+			if(typeof oriValue === "object" && typeof value === "object" && !common.isEmpty(value)) {
+				merge(oriValue, value);
+			} else {
+				obj1[key] = value;
+			}
+		});
+	}
+
+	common.merge = function (mergedObj) {
+		for(var i = 1 ; i < arguments.length ; i += 1) {
+			var obj = arguments[i];
+			merge(mergedObj, obj);
+		}
+
+		return mergedObj;
+	};
+
+	// ============================ String ============================
+	common.string = {};
+	common.string.safeText = function (str) {
+		return str
+			.replace(/&/g, '&amp;')
+			.replace(/</g, '&lt;')
+			.replace(/>/g, '&gt;');
+	};
+
+	common.string.capitalize = function (str) {
+		return (str + "").replace(/\b\w/g, function(match) {
+			return match.toUpperCase();
+		});
+	};
+
+	common.string.preFill = function (str, key, len) {
+		str = str + "";
+		len = len || 2;
+		while(str.length < len) {
+			str = key + str;
+		}
+		return str;
+	};
+
+	// ============================ Array =============================
+	common.array = {};
+
+	common.array.findIndex = function(val, list, path, findAll, caseSensitive) {
+		var _list = [];
+		val = caseSensitive === false ? (val + "").toUpperCase() : val;
+
+		for(var i = 0 ; i < list.length ; i += 1) {
+			var unit = list[i];
+			var _val = common.getValueByPath(unit, path);
+			_val = caseSensitive === false ? (_val + "").toUpperCase() : _val;
+
+			if(_val === val) {
+				if(!findAll) return i;
+				_list.push(i);
+			}
+		}
+
+		return findAll ? _list: -1;
+	};
+
+	common.array.find = function(val, list, path, findAll, caseSensitive) {
+		var index = common.array.findIndex(val, list, path, findAll, caseSensitive);
+
+		if(findAll) {
+			return $.map(index, function (index) {
+				return list[index];
+			});
+		} else {
+			return index === -1 ? null : list[index];
+		}
+	};
+
+	common.array.minus = function (list1, list2, path1, path2) {
+		if(arguments.length === 3) path2 = path1;
+		var list = [];
+		$.each(list1, function (i, item) {
+			var val1 = common.getValueByPath(item, path1);
+			if(!common.array.find(val1, list2, path2)) {
+				list.push(item);
+			}
+		});
+		return list;
+	};
+
+	common.array.doSort = function (list, path, asc, sortList) {
+		var sortFunc;
+		sortList = sortList || [];
+
+		if(asc !== false) {
+			sortFunc = function (obj1, obj2) {
+				var val1 = common.getValueByPath(obj1, path);
+				var val2 = common.getValueByPath(obj2, path);
+
+				var index1 = common.array.findIndex(val1, sortList);
+				var index2 = common.array.findIndex(val2, sortList);
+
+				if(index1 !== -1 && index2 === -1) {
+					return -1;
+				} else if(index1 == -1 && index2 !== -1) {
+					return 1;
+				} else if(index1 !== -1 && index2 !== -1) {
+					return index1 - index2;
+				}
+
+				if (val1 === val2) {
+					return 0;
+				} else if (val1 === null || val1 === undefined || val1 < val2) {
+					return -1;
+				}
+				return 1;
+			};
+		} else {
+			sortFunc = function (obj1, obj2) {
+				var val1 = common.getValueByPath(obj1, path);
+				var val2 = common.getValueByPath(obj2, path);
+
+				var index1 = common.array.findIndex(val1, sortList);
+				var index2 = common.array.findIndex(val2, sortList);
+
+				if(index1 !== -1 && index2 === -1) {
+					return -1;
+				} else if(index1 == -1 && index2 !== -1) {
+					return 1;
+				} else if(index1 !== -1 && index2 !== -1) {
+					return index1 - index2;
+				}
+
+				if (val1 === val2) {
+					return 0;
+				} else if (val1 === null || val1 === undefined || val1 < val2) {
+					return 1;
+				}
+				return -1;
+			};
+		}
+
+		return list.sort(sortFunc);
+	};
+
+	// =========================== Deferred ===========================
+	common.deferred = {};
+
+
+	common.deferred.all = function (deferredList) {
+		var deferred = $.Deferred();
+		var successList = [];
+		var failureList = [];
+		var hasFailure = false;
+		var rest = deferredList.length;
+		function doCheck() {
+			rest -= 1;
+			if(rest === 0) {
+				if(hasFailure) {
+					deferred.reject(failureList);
+				} else {
+					deferred.resolve(successList);
+				}
+			}
+		}
+
+		$.each(deferredList, function (i, deferred) {
+			if(deferred && deferred.then) {
+				deferred.then(function (data) {
+					successList[i] = data;
+				}, function (data) {
+					failureList[i] = data;
+					hasFailure = true;
+				}).always(doCheck);
+			} else {
+				successList[i] = deferred;
+				doCheck();
+			}
+		});
+
+		return deferred;
+	};
+
+	// ============================ Number ============================
+	common.number = {};
+
+	common.number.isNumber = function (num) {
+		return typeof num === "number" && !isNaN(num);
+	};
+
+	common.number.toFixed = function (num, fixed) {
+		if(!common.number.isNumber(num)) return "-";
+		num = Number(num);
+		return num.toFixed(fixed || 0);
+	};
+
+	common.number.format = function (num, fixed) {
+		if(!common.number.isNumber(num)) return "-";
+		return common.number.toFixed(num, fixed).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+	};
+
+	common.number.abbr = function (number, isByte, digits) {
+		digits = digits || 2;
+		var decPlaces = Math.pow(10, digits);
+		var abbrev = isByte ? ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['K', 'M', 'B', 'T', 'Q'];
+		var base = isByte ? 1024 : 1000;
+		var sign = number < 0 ? -1 : 1;
+		var unit = '';
+		number = Math.abs(number);
+
+		for(var i = abbrev.length - 1; i >= 0; i--) {
+			var size = Math.pow(base, i + 1);
+			if(size <= number) {
+				number = Math.round(number * decPlaces / size) / decPlaces;
+				if((number === base) && (i < abbrev.length - 1)) {
+					number = 1;
+					i++;
+				}
+				unit = abbrev[i];
+				break;
+			}
+		}
+		unit = unit ? unit : "";
+		return (number * sign).toFixed(digits) + unit;
+	};
+
+	common.number.compare = function (num1, num2) {
+		if(!common.number.isNumber(num1) || !common.number.isNumber(num2)) return "-";
+		if(num1 === 0) return 'N/A';
+		return (num2 - num1) / num1;
+	};
+
+	common.number.inRange = function (rangList, num) {
+		for(var i = 0 ; i < rangList.length - 1 ; i += 1) {
+			var start = rangList[i];
+			var end = rangList[i + 1];
+			if(start <= num && num < end) return i;
+		}
+		return rangList.length - 1;
+	};
+
+	common.number.sum = function (list, path) {
+		var total = 0;
+		$.each(list, function (i, obj) {
+			var value = common.getValueByPath(obj, path);
+			if(typeof value === "number" && !isNaN(value)) {
+				total += value;
+			}
+		});
+		return total;
+	};
+})();

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/js/components/chart.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/components/chart.js b/eagle-server/src/main/webapp/app/dev/public/js/components/chart.js
new file mode 100644
index 0000000..99f74d5
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/components/chart.js
@@ -0,0 +1,188 @@
+/*
+ * 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 eagleComponents = angular.module('eagle.components');
+
+	eagleComponents.service('Chart', function () {
+		return {
+			color: [ "#0073b7", "#dd4b39", "#00a65a", "#f39c12", "#605ca8", "#001F3F", "#39CCCC", "#D81B60", "#3c8dbc", "#f56954", "#00c0ef", "#3D9970", "#FF851B"  , "#01FF70", "#F012BE"],
+			//color: ['#4285f4', '#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae','#749f83',  '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3'],
+			charts: {}
+		};
+	});
+
+	eagleComponents.directive('chart', function(Chart) {
+		var charts = Chart.charts;
+
+		function chartResize() {
+			setTimeout(function () {
+				$.each(charts, function (id, chart) {
+					chart.resize();
+				});
+			}, 310);
+		}
+
+		$(window).resize(chartResize);
+		$("body").on("expanded.pushMenu collapsed.pushMenu", chartResize);
+
+		return {
+			restrict: 'AE',
+			scope: {
+				title: "@?title",
+				series: "=",
+				category: "=?category",
+				categoryFunc: "=?categoryFunc",
+				xTitle: "@?xTitle",
+				yTitle: "@?yTitle",
+
+				option: "=?option",
+
+				click: "=?ngClick",
+
+				chart: "@?chart"
+			},
+			controller: function ($scope, $element, $attrs, Time) {
+				var i;
+				var lastTooltipEvent;
+				var chart = echarts.init($element[0]);
+				charts[chart.id] = chart;
+
+				function refreshChart() {
+					var maxYAxis = 0;
+					var legendList = [];
+					var categoryList = $scope.category ? $scope.category : [];
+
+					var seriesList = $.map($scope.series || [], function (series, id) {
+						if(id === 0 && !$scope.category) {
+							//var preDate = -1;
+							categoryList = $.map(series.data, function (point) {
+								/*ivar time = new Time(point.x);
+								f(preDate !== time.date()) {
+									preDate = time.date();
+									return Time.format(point.x, "MMM.D HH:mm");
+								}*/
+								if($scope.categoryFunc) {
+									return $scope.categoryFunc(point.x);
+								}
+								return Time.format(point.x, "HH:mm");
+							});
+						}
+
+						legendList.push(series.name);
+						if(series.yAxisIndex) maxYAxis = Math.max(series.yAxisIndex, maxYAxis);
+
+						return $.extend({}, series, {
+							data: $scope.category ? series.data : $.map(series.data, function (point) {
+								return point.y;
+							})
+						});
+					});
+
+					var yAxis = [];
+					for(i = 0 ; i <= maxYAxis ; i += 1) {
+						yAxis.push({
+							name: $scope.yTitle,
+							type: "value"
+						});
+					}
+
+					var option = {
+						color: Chart.color.concat(),
+						title: [{text: $scope.title}],
+						tooltip: {trigger: 'axis'},
+						legend: [{
+							data: legendList
+						}],
+						grid: {
+							top: '30',
+							left: '0',
+							right: '0',
+							bottom: '0',
+							containLabel: true
+						},
+						xAxis: {
+							name: $scope.xTitle,
+							type: 'category',
+							data: categoryList,
+							axisTick: { show: false }
+						},
+						yAxis: yAxis,
+						series: seriesList
+					};
+
+					if($scope.option) {
+						option = common.merge(option, $scope.option);
+					}
+
+					chart.setOption(option);
+				}
+
+				// Event handle
+				var chartClick = false;
+				chart.on("click", function (e) {
+					if($scope.click) {
+						if($scope.click(e)) {
+							refreshChart();
+						}
+					}
+					chartClick = true;
+				});
+
+				chart.getZr().on('click', function () {
+					if(!chartClick && $scope.click) {
+						if($scope.click($.extend({
+							componentType: "tooltip"
+						}, lastTooltipEvent))) {
+							refreshChart();
+						}
+					}
+					chartClick = false;
+				});
+
+				chart.on('showtip', function (e) {
+					lastTooltipEvent = e;
+				});
+
+				// Insert chart object to parent scope
+				if($attrs.chart) {
+					$scope.$parent.$parent[$attrs.chart] = chart;
+				}
+
+				chart.refresh = function () {
+					refreshChart();
+				};
+
+				// Render
+				refreshChart();
+				$scope.$watch("series", refreshChart);
+
+				$scope.$on('$destroy', function() {
+					delete charts[chart.id];
+					chart.dispose();
+
+					delete $scope.$parent.$parent[$attrs.chart];
+				});
+			},
+			template: '<div>Loading...</div>',
+			replace: true
+		};
+	});
+})();

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/src/main/webapp/app/dev/public/js/components/main.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/components/main.js b/eagle-server/src/main/webapp/app/dev/public/js/components/main.js
new file mode 100644
index 0000000..0c8a54c
--- /dev/null
+++ b/eagle-server/src/main/webapp/app/dev/public/js/components/main.js
@@ -0,0 +1,24 @@
+/*
+ * 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';
+
+	angular.module('eagle.components', []);
+})();