http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-server/ui-build.sh
----------------------------------------------------------------------
diff --git a/eagle-server/ui-build.sh b/eagle-server/ui-build.sh
new file mode 100644
index 0000000..9f17ba6
--- /dev/null
+++ b/eagle-server/ui-build.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# 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.
+
+echo "=============== Web APP Building Start ==============="
+echo "Environment Check..."
+# Pre-build check
+if [ -z "$(command -v git)" ]
+then
+       echo "git not installed!"
+       exit 1
+fi
+if [ -z "$(command -v npm)" ]
+then
+       echo "npm not installed!"
+       exit 1
+fi
+echo "Environment Check...Pass"
+
+# npm install
+cd src/main/webapp/app
+echo "npm install..."
+npm install
+
+# grunt build
+echo "building..."
+npm run build

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/Gruntfile.js
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/Gruntfile.js 
b/eagle-webservice/src/main/webapp/Gruntfile.js
deleted file mode 100644
index d2a3a42..0000000
--- a/eagle-webservice/src/main/webapp/Gruntfile.js
+++ /dev/null
@@ -1,175 +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.
-*/
-'use strict';
-
-module.exports = function (grunt) {
-       // Project configuration.
-       grunt.initConfig({
-               pkg: grunt.file.readJSON('package.json'),
-               config: grunt.file.readJSON('grunt.json'),
-
-               jshint: {
-                       options: {
-                               browser: true,
-                               globals: {
-                                       $: true,
-                                       jQuery: true,
-                                       moment: true
-                               }
-                       },
-                       all: [
-                               'app/**/*.js'
-                       ]
-               },
-
-               clean: {
-                       build: ['ui/', 'tmp/'],
-                       tmp: ['tmp/'],
-                       ui: ['ui/']
-               },
-               concat: {
-                       app: {
-                               src: [
-                                       'app/public/js/app.js',
-
-                                       'app/public/js/srv/main.js',
-                                       'app/public/js/srv/**.js',
-
-                                       'app/public/js/app.*.js',
-
-                                       'app/public/js/common.js',
-
-                                       'app/public/js/components/main.js',
-                                       'app/public/js/components/**.js',
-                                       'app/public/js/components/**/**.js',
-
-                                       'app/public/js/ctrl/main.js',
-                                       'app/public/js/ctrl/*.js'
-                               ],
-                               dest: 'tmp/public/js/scripts.js'
-                       },
-                       js: '<%= config.concat.js %>',
-                       css: {
-                               options: {
-                                       process: function(src, filepath) {
-                                               return "@import 
url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic);"
 +
-                                               src.replace('@import 
url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic);',
 '');
-                                       }
-                               },
-                               src: '<%= config.concat.css.src %>',
-                               dest: '<%= config.concat.css.dest %>'
-                       }
-               },
-               'regex-replace': {
-                       strict: {
-                               src: ['tmp/public/js/scripts.js'],
-                               actions: [
-                                       {
-                                               name: 'use strict',
-                                               search: '\\\'use strict\\\';?',
-                                               replace: '',
-                                               flags: 'gmi'
-                                       },
-                                       {
-                                               name: 'build timestamp',
-                                               search: '\\/\\/ GRUNT 
REPLACEMENT\\: eagleApp\\.buildTimestamp \\= TIMESTAMP',
-                                               replace: 
'eagleApp.buildTimestamp = ' + (+new Date()) + ';',
-                                               flags: 'gmi'
-                                       }
-                               ]
-                       }
-               },
-               uglify: {
-                       ui: {
-                               options: {
-                                       mangle: false
-                               },
-                               files: [
-                                       {
-                                               src: 'tmp/public/js/scripts.js',
-                                               dest: 
'tmp/public/js/scripts.min.js'
-                                       },
-                                       {
-                                               expand: true,
-                                               src: '**/*.js',
-                                               dest: 'tmp/feature',
-                                               cwd: 'app/public/feature'
-                                       }
-                               ]
-                       }
-               },
-               cssmin: {
-                       ui: {
-                               files: {
-                                       'tmp/public/css/styles.css': 
['app/public/css/main.css', 'app/public/css/animation.css']
-                               }
-                       }
-               },
-               htmlrefs: {
-                       ui: {
-                               src: 'app/index.html',
-                               dest: "tmp/index.html"
-                       }
-               },
-               copy: {
-                       feature: {
-                               files: [
-                                       {expand: true, cwd: 'app/', src: 
['public/feature/**'], dest: 'tmp'}
-                               ]
-                       },
-                       ui: {
-                               files: [
-                                       {expand: true, cwd: 'tmp/', src: 
['**'], dest: 'ui'},
-                                       {expand: true, cwd: 'app/', src: 
['public/images/**', 'partials/**'], dest: 'ui'},
-                                       {expand: true, cwd: 
'node_modules/font-awesome/', src: ['fonts/**'], dest: 'ui/public'},
-                                       {expand: true, cwd: 
'node_modules/bootstrap/', src: ['fonts/**'], dest: 'ui/public'}
-                               ]
-                       }
-               }
-       });
-
-       grunt.loadNpmTasks('grunt-contrib-jshint');
-       grunt.loadNpmTasks('grunt-contrib-clean');
-       grunt.loadNpmTasks('grunt-contrib-concat');
-       grunt.loadNpmTasks('grunt-contrib-uglify');
-       grunt.loadNpmTasks('grunt-contrib-cssmin');
-       grunt.loadNpmTasks('grunt-htmlrefs');
-       grunt.loadNpmTasks('grunt-regex-replace');
-       grunt.loadNpmTasks('grunt-contrib-copy');
-
-       grunt.registerTask('default', [
-               // jshint
-               'jshint:all',
-               // Clean Env
-               'clean:build',
-               // Compress JS
-               'copy:feature',
-               'concat:app',
-               'regex-replace:strict',
-               'uglify',
-               'concat:js',
-               // Compress CSS
-               'cssmin',
-               'concat:css',
-               // Pass HTML Resources
-               'htmlrefs',
-               'copy:ui',
-               // Clean Env
-               'clean:tmp'
-       ]);
-};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/README.md
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/README.md 
b/eagle-webservice/src/main/webapp/README.md
deleted file mode 100644
index b4168d5..0000000
--- a/eagle-webservice/src/main/webapp/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Apache Eagle Web APP
-==
-
-Web client for Apache Eagle
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/index.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/index.html 
b/eagle-webservice/src/main/webapp/_app/index.html
new file mode 100644
index 0000000..7cd3e25
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/index.html
@@ -0,0 +1,281 @@
+<!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-app="eagleApp" 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/styles.min.css -->
+               <link href="public/css/main.css" rel="stylesheet" 
type="text/css" media="screen">
+               <link href="public/css/animation.css" rel="stylesheet" 
type="text/css" media="screen">
+               <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" />
+               <!-- 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">
+                                                       <!-- Admin error list 
-->
+                                                       <li class="dropdown" 
ng-show="ServiceError.list.length">
+                                                               <a 
class="dropdown-toggle" data-toggle="dropdown" role="button" 
aria-haspopup="true" aria-expanded="false">
+                                                                       <i 
class="fa fa-exclamation-triangle" ng-class="{blink: 
ServiceError.hasUnread}"></i>
+                                                               </a>
+                                                               <ul 
class="dropdown-menu">
+                                                                       <li 
ng-repeat="error in ServiceError.list">
+                                                                               
<a ng-click="ServiceError.showError(error);">
+                                                                               
        <span class="fa" ng-class="{'fa-envelope': !error._read, 'fa-check': 
error._read}"></span>
+                                                                               
        {{error.title}}
+                                                                               
</a>
+                                                                       </li>
+                                                                       <li 
role="separator" class="divider"></li>
+                                                                       <li>
+                                                                               
<a ng-click="ServiceError.clearAll();">
+                                                                               
        <span class="fa fa-trash"></span>
+                                                                               
        Clear All
+                                                                               
</a>
+                                                                       </li>
+                                                               </ul>
+                                                       </li>
+
+                                                       <!-- Site -->
+                                                       <li class="dropdown" 
ng-show="!PageConfig.hideSite && !PageConfig.lockSite">
+                                                               <a 
class="dropdown-toggle" data-toggle="dropdown" role="button" 
aria-haspopup="true" aria-expanded="false">
+                                                                       <i 
class="fa fa-server"></i>
+                                                                       
{{Site.current().tags.site}}
+                                                                       <i 
class="fa fa-caret-down"></i>
+                                                               </a>
+                                                               <ul 
class="dropdown-menu">
+                                                                       <li 
ng-repeat="_site in Site.list" ng-if="_site.enabled">
+                                                                               
<a ng-click="Site.current(_site);">
+                                                                               
        <span class="fa fa-database"></span> {{_site.tags.site}}
+                                                                               
</a>
+                                                                       </li>
+                                                               </ul>
+                                                       </li>
+                                                       <li class="dropdown" 
ng-show="PageConfig.lockSite">
+                                                               <a>
+                                                                       <i 
class="fa fa-server"></i>
+                                                                       
{{Site.current().tags.site}}
+                                                               </a>
+                                                       </li>
+
+                                                       <!-- User -->
+                                                       <li class="dropdown 
user user-menu" ng-hide="PageConfig.hideUser">
+                                                               <a 
class="dropdown-toggle" data-toggle="dropdown" role="button" 
aria-haspopup="true" aria-expanded="false">
+                                                                       <i 
class="fa fa-user"></i>
+                                                                       
{{Auth.userProfile.username}}
+                                                               </a>
+                                                               <ul 
class="dropdown-menu">
+                                                                       <!-- 
User image -->
+                                                                       <li 
class="user-header">
+                                                                               
<span class="img-circle">
+                                                                               
        <span class="fa fa-user" alt="User Image"></span>
+                                                                               
</span>
+                                                                               
<p>
+                                                                               
        {{Auth.userProfile.username}}
+                                                                               
        <small>
+                                                                               
                <span ng-repeat="role in 
Auth.userProfile.authorities">{{role.authority}} </span>
+                                                                               
        </small>
+                                                                               
</p>
+                                                                       </li>
+                                                                       <!-- 
Menu Footer-->
+                                                                       <li 
class="user-footer">
+                                                                               
<div class="pull-left" ng-if="Auth.isRole('ROLE_ADMIN')">
+                                                                               
        <a href="#/config/site" class="btn btn-default btn-flat">Management</a>
+                                                                               
</div>
+                                                                               
<div class="pull-right">
+                                                                               
        <a ng-click="logout();" class="btn btn-default btn-flat">Sign out</a>
+                                                                               
</div>
+                                                                       </li>
+                                                               </ul>
+                                                       </li>
+                                               </ul>
+                                       </div>
+
+                                       <!-- Applications -->
+                                       <div 
ng-hide="PageConfig.hideApplication">
+                                               <button type="button" 
class="navbar-toggle collapsed" data-toggle="collapse" 
data-target="#moduleMenu">
+                                                       <span 
class="sr-only">Toggle navigation</span>
+                                                       <span class="fa 
fa-map"></span>
+                                               </button>
+                                               <div class="collapse 
navbar-collapse" id="moduleMenu">
+                                                       <ul class="nav 
navbar-nav">
+                                                               <li 
ng-repeat="_grp in Site.current().applicationGroupList" 
ng-if="_grp.enabledList.length"
+                                                                       
class="dropdown" ng-class="{active: Application.current().group === _grp.name}">
+                                                                       <a 
class="dropdown-toggle" data-toggle="dropdown" role="button" 
aria-haspopup="true" aria-expanded="false">
+                                                                               
{{_grp.name}}
+                                                                       </a>
+                                                                       <ul 
class="dropdown-menu">
+                                                                               
<li ng-repeat="_app in _grp.enabledList">
+                                                                               
        <a ng-click="Application.current(_app);">
+                                                                               
                <span class="fa fa-cubes"></span> {{_app.displayName}}
+                                                                               
        </a>
+                                                                               
</li>
+                                                                       </ul>
+                                                               </li>
+                                                       </ul>
+                                               </div>
+                                       </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 class="header">
+                                                       
{{Application.current().group || 'Application'}} >
+                                                       
{{Application.current().displayName || 'Features'}}
+                                               </li>
+                                               <li ng-repeat="page in 
PageConfig.navConfig.pageList track by $index" ng-class="getNavClass(page)" 
ng-show="getNavVisible(page)">
+                                                       <a href="{{page.url}}">
+                                                               <i class="fa 
fa-{{page.icon}}"></i> <span>{{page.title}}</span> 
+                                                       </a>
+                                               </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.hideSidebar">
+                                       <h1>
+                                               <span 
class="pageTitle">{{PageConfig.pageTitle}}</span>
+                                               <small 
class="pageSubTitle">{{PageConfig.pageSubTitle}}</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 -->
+
+               <!-- ref:js public/js/doc.js -->
+               <script src="../node_modules/jquery/dist/jquery.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/admin-lte/dist/js/app.min.js"></script>
+               <script src="../node_modules/angular/angular.js"></script>
+               <script 
src="../node_modules/angular-resource/angular-resource.js"></script>
+               <script 
src="../node_modules/angular-route/angular-route.js"></script>
+               <script 
src="../node_modules/angular-animate/angular-animate.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.js"></script>
+               <script src="../node_modules/d3/d3.js"></script>
+               <script 
src="../node_modules/zombiej-nvd3/build/nv.d3.js"></script>
+
+               <!-- Application -->
+               <script src="public/js/app.js" type="text/javascript" 
charset="utf-8"></script>
+
+               <!-- Service -->
+               <script src="public/js/srv/main.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/srv/applicationSrv.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/srv/authorizationSrv.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/srv/entitiesSrv.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/srv/siteSrv.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/srv/pageSrv.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/srv/wrapStateSrv.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/srv/uiSrv.js" type="text/javascript" 
charset="utf-8"></script>
+
+               <!-- Misc -->
+               <script src="public/js/app.ui.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/app.time.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/app.config.js" type="text/javascript" 
charset="utf-8"></script>
+
+               <script src="public/js/common.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/tabs.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/components/file.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/components/charts/line3d.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/components/nvd3.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/components/sortable.js" 
type="text/javascript" charset="utf-8"></script>
+
+               <!-- Controllers -->
+               <script src="public/js/ctrl/main.js" type="text/javascript" 
charset="utf-8"></script>
+               <script src="public/js/ctrl/authController.js" 
type="text/javascript" charset="utf-8"></script>
+               <script src="public/js/ctrl/configurationController.js" 
type="text/javascript" charset="utf-8"></script>
+               <!-- endref -->
+       </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/partials/config/application.html
----------------------------------------------------------------------
diff --git 
a/eagle-webservice/src/main/webapp/_app/partials/config/application.html 
b/eagle-webservice/src/main/webapp/_app/partials/config/application.html
new file mode 100644
index 0000000..0bf194c
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/partials/config/application.html
@@ -0,0 +1,124 @@
+<!--
+  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-info">
+       <div class="box-header with-border">
+               <h3 class="box-title">
+                       <span class="fa fa-cogs"></span>
+                       Configuration
+                       <small class="text-danger" ng-show="changed">
+                               <span class="label label-warning 
label-sm">Unsaved</span>
+                       </small>
+               </h3>
+       </div><!-- /.box-header -->
+
+       <div class="box-body">
+               <div class="row">
+                       <div class="col-md-3">
+                               <ul class="nav nav-pills nav-stacked">
+                                       <li 
class="disabled"><a>Application</a></li>
+                                       <li role="presentation" 
ng-repeat="_application in Application.list track by $index" ng-class="{active: 
application === _application}">
+                                               <a 
ng-click="setApplication(_application)">
+                                                       <span class="fa 
fa-server"></span>
+                                                       
{{_application.tags.application}}
+                                                       <span 
ng-if="_application.alias">({{_application.alias}})</span>
+                                               </a>
+                                       </li>
+
+                                       <li>
+                                               <a class="text-light-blue" 
ng-click="newApplication()" ng-disabled="_pageLock">
+                                                       <span class="fa 
fa-plus-square"></span>
+                                                       New Application
+                                               </a>
+                                       </li>
+                               </ul>
+                       </div>
+
+                       <div class="col-md-9">
+                               <a class="pull-right btn btn-danger btn-xs" 
ng-click="deleteApplication(application)" ng-disabled="_pageLock">
+                                       <span class="fa fa-trash-o"></span>
+                                       Delete Application
+                               </a>
+
+                               <!-- Title -->
+                               <h3 class="guideline">
+                                       Application
+                                       
<small>{{application.tags.application}}</small>
+                               </h3>
+                               <hr/>
+
+                               <!-- Config -->
+                               <div class="form-group">
+                                       <label for="displayName">Display 
Name</label>
+                                       <input type="text" class="form-control" 
id="displayName" placeholder="(Optional) Display name." 
ng-model="applications[application.tags.application].alias">
+                               </div>
+                               <div class="form-group">
+                                       <label 
for="applicationGroup">Group</label>
+                                       <input type="text" class="form-control" 
id="applicationGroup" placeholder="(Optional) Group name" 
ng-model="applications[application.tags.application].groupName">
+                               </div>
+                               <div class="form-group">
+                                       <label 
for="applicationDescription">Description</label>
+                                       <textarea id="applicationDescription" 
class="form-control" placeholder="(Optional) Application description" rows="2" 
ng-model="applications[application.tags.application].description"></textarea>
+                               </div>
+                               <div class="form-group">
+                                       <label 
for="applicationConfiguration">Configuration</label>
+                                       <span 
class="text-danger">{{configCheck(applications[application.tags.application].config)}}</span>
+                                       <textarea id="applicationConfiguration" 
class="form-control" placeholder="Application configuration. Feature can read 
this " rows="5" 
ng-model="applications[application.tags.application].config"></textarea>
+                               </div>
+
+                               <!-- Feature -->
+                               <label>* Feature</label>
+                               <div class="row">
+                                       <div class="col-sm-6">
+                                               <h1 class="text-muted 
text-center" 
ng-show="applications[application.tags.application].features.length === 0">No 
feature in using</h1>
+                                               <ul class="products-list 
product-list-in-box fixed-height" 
ng-show="applications[application.tags.application].features.length !== 0">
+                                                       <li class="item" 
ng-repeat="feature in applications[application.tags.application].features track 
by $index" ng-class="{active: _feature === feature}">
+                                                               <div 
class="product-operation">
+                                                                       <a 
class="fa fa-chevron-up" ng-click="moveFeature(feature, 
applications[application.tags.application].features, -1)"></a>
+                                                                       <a 
class="fa fa-chevron-down" ng-click="moveFeature(feature, 
applications[application.tags.application].features, 1)"></a>
+                                                               </div>
+                                                               <div 
class="product-info">
+                                                                       <a 
class="fa fa-times pull-right" ng-click="removeFeature(feature, 
applications[application.tags.application])"></a>
+                                                                       <span 
class="product-title">{{feature}}</span>
+                                                                       <span 
class="product-description">{{Application.featureList.set[feature].description}}</span>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </div>
+                                       <div class="col-sm-6">
+                                               <ul class="products-list 
product-list-in-box fixed-height">
+                                                       <li class="item" 
ng-repeat="feature in 
applications[application.tags.application].optionalFeatures track by $index">
+                                                               <button 
class="btn btn-lg btn-primary pull-left" ng-click="addFeature(feature, 
applications[application.tags.application])" ng-disabled="_pageLock">
+                                                                       <span 
class="fa fa-star-o"></span>
+                                                               </button>
+                                                               <div 
class="product-info">
+                                                                       <span 
class="product-title">{{feature}}</span>
+                                                                       <span 
class="product-description">{{Application.featureList.set[feature].description}}</span>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </div>
+                               </div>
+                       </div>
+               </div>
+       </div><!-- /.box-body -->
+
+       <div class="box-footer clearfix">
+               <button class="btn btn-primary" ng-click="saveAll()" 
ng-disabled="_pageLock">Save All</button>
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/partials/config/feature.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/partials/config/feature.html 
b/eagle-webservice/src/main/webapp/_app/partials/config/feature.html
new file mode 100644
index 0000000..945d90b
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/partials/config/feature.html
@@ -0,0 +1,85 @@
+<!--
+  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-info">
+       <div class="box-header with-border">
+               <h3 class="box-title">
+                       <span class="fa fa-cogs"></span>
+                       Configuration
+                       <small class="text-danger" ng-show="changed">
+                               <span class="label label-warning 
label-sm">Unsaved</span>
+                       </small>
+               </h3>
+       </div><!-- /.box-header -->
+
+       <div class="box-body">
+               <div class="row">
+                       <div class="col-md-3">
+                               <ul class="nav nav-pills nav-stacked">
+                                       <li class="disabled">
+                                               <a>Feature</a>
+                                       </li>
+                                       <li role="presentation" 
ng-repeat="_feature in Application.featureList" ng-class="{active: feature === 
_feature}">
+                                               <a 
ng-click="setFeature(_feature)">
+                                                       <span class="fa 
fa-leaf" ng-class="{'text-danger': _feature._loaded === false}" 
uib-tooltip="Module load failed!" tooltip-enable="_feature._loaded === 
false"></span>
+                                                       
{{_feature.tags.feature}}
+                                               </a>
+                                       </li>
+                                       <li>
+                                               <a class="text-light-blue" 
ng-click="newFeature()" ng-disabled="_pageLock">
+                                                       <span class="fa 
fa-plus-square"></span>
+                                                       New Feature
+                                               </a>
+                                       </li>
+                               </ul>
+                       </div>
+
+                       <div class="col-md-9">
+                               <a class="pull-right btn btn-danger btn-xs" 
ng-click="deleteFeature(feature)" ng-disabled="_pageLock">
+                                       <span class="fa fa-trash-o"></span>
+                                       Delete Feature
+                               </a>
+
+                               <h3 class="guideline">
+                                       <span class="fa fa-exclamation-triangle 
text-danger" uib-tooltip="Module load failed!" ng-show="feature._loaded === 
false"></span>
+                                       {{feature.tags.feature}}
+                               </h3>
+                               <hr/>
+
+                               <p class="text text-muted">
+                                       Will load the start up file 
<code>controller.js</code> from 
<code>public/feature/{{feature.tags.feature}}</code>.
+                                       If you are developing customized 
feature, please reference provided feature.
+                               </p>
+
+                               <!-- Config -->
+                               <div class="form-group">
+                                       <label 
for="featureVersion">Version</label>
+                                       <input id="featureVersion" type="text" 
class="form-control" placeholder="(Optional) Feature version." 
ng-model="features[feature.tags.feature].version">
+                               </div>
+                               <div class="form-group">
+                                       <label 
for="featureDescription">Description</label>
+                                       <textarea id="featureDescription" 
class="form-control" placeholder="(Optional) Feature description." rows="10" 
ng-model="features[feature.tags.feature].description"></textarea>
+                               </div>
+                       </div>
+               </div>
+       </div><!-- /.box-body -->
+
+       <div class="box-footer clearfix">
+               <button class="btn btn-primary" ng-click="saveAll()" 
ng-disabled="_pageLock">Save All</button>
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/partials/config/site.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/partials/config/site.html 
b/eagle-webservice/src/main/webapp/_app/partials/config/site.html
new file mode 100644
index 0000000..f7d43eb
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/partials/config/site.html
@@ -0,0 +1,115 @@
+<!--
+  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-info">
+       <div class="box-header with-border">
+               <h3 class="box-title">
+                       <span class="fa fa-cogs"></span>
+                       Configuration
+                       <small class="text-danger" ng-show="changed">
+                               <span class="label label-warning 
label-sm">Unsaved</span>
+                       </small>
+               </h3>
+       </div><!-- /.box-header -->
+
+       <div class="box-body">
+               <div class="row">
+                       <div class="col-md-3">
+                               <ul class="nav nav-pills nav-stacked">
+                                       <li class="disabled"><a>Site</a></li>
+                                       <li role="presentation" 
ng-repeat="_site in Site.list track by $index" ng-class="{active: site === 
_site}">
+                                               <a ng-click="setSite(_site)">
+                                                       <span class="fa 
fa-server"></span>
+                                                       {{_site.tags.site}}
+                                               </a>
+                                       </li>
+
+                                       <li>
+                                               <a class="text-light-blue" 
ng-click="newSite()" ng-disabled="_pageLock">
+                                                       <span class="fa 
fa-plus-square"></span>
+                                                       New Site
+                                               </a>
+                                       </li>
+                               </ul>
+                       </div>
+
+                       <div class="col-md-9">
+                               <a class="pull-right btn btn-danger btn-xs" 
ng-click="deleteSite(site)" ng-disabled="_pageLock">
+                                       <span class="fa fa-trash-o"></span>
+                                       Delete Site
+                               </a>
+
+                               <!-- Title -->
+                               <h3 class="guideline">
+                                       Site
+                                       <small>{{site.tags.site}}</small>
+                               </h3>
+                               <hr/>
+
+                               <!-- Config -->
+                               <div class="checkbox">
+                                       <label>
+                                               <input type="checkbox" 
ng-checked="sites[site.tags.site].enabled" 
ng-click="sites[site.tags.site].enabled = !sites[site.tags.site].enabled">
+                                               <strong>Enabled</strong>
+                                       </label>
+                               </div>
+                               <hr/>
+
+                               <!-- Application -->
+                               <label>* Application</label>
+                               <div class="row">
+                                       <div class="col-sm-6">
+                                               <h1 class="text-muted 
text-center" ng-show="sites[site.tags.site].applications.length === 0">No 
application in using</h1>
+                                               <ul class="products-list 
product-list-in-box fixed-height" 
ng-show="sites[site.tags.site].applications.length !== 0">
+                                                       <li class="item" 
ng-repeat="application in sites[site.tags.site].applications track by $index" 
ng-class="{active: _application === application}">
+                                                               <div 
class="product-operation single">
+                                                                       <span 
class="fa fa-cubes"></span>
+                                                               </div>
+                                                               <div 
class="product-info">
+                                                                       <a 
class="fa fa-times pull-right" ng-click="removeApplication(application, 
sites[site.tags.site])"></a>
+                                                                       <span 
class="product-title">
+                                                                               
<a class="fa fa-cog" ng-click="setApplication(application)"></a>
+                                                                               
{{application.tags.application}}
+                                                                       </span>
+                                                                       <span 
class="product-description">{{Application.list.set[application.tags.application].description}}</span>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </div>
+                                       <div class="col-sm-6">
+                                               <ul class="products-list 
product-list-in-box fixed-height">
+                                                       <li class="item" 
ng-repeat="application in sites[site.tags.site].optionalApplications track by 
$index">
+                                                               <button 
class="btn btn-lg btn-primary pull-left" ng-click="addApplication(application, 
sites[site.tags.site])" ng-disabled="_pageLock">
+                                                                       <span 
class="fa fa-star-o"></span>
+                                                               </button>
+                                                               <div 
class="product-info">
+                                                                       <span 
class="product-title">{{application.tags.application}}</span>
+                                                                       <span 
class="product-description">{{Application.list.set[application.tags.application].description}}</span>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </div>
+                               </div>
+                       </div>
+               </div>
+       </div><!-- /.box-body -->
+
+       <div class="box-footer clearfix">
+               <button class="btn btn-primary" ng-click="saveAll()" 
ng-disabled="_pageLock">Save All</button>
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/partials/landing.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/partials/landing.html 
b/eagle-webservice/src/main/webapp/_app/partials/landing.html
new file mode 100644
index 0000000..a2e0f47
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/partials/landing.html
@@ -0,0 +1,30 @@
+<!--
+  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.
+  -->
+
+<p class="lead">
+       <span ng-if="!Application.current()">Current site do not use any 
application.</span>
+       <span ng-if="Application.current()">Current application do not install 
any feature.</span>
+
+       <span ng-if="Auth.isRole('ROLE_ADMIN')">
+               Click
+               <a href="#/config/site" ng-if="!Application.current()">here</a>
+               <a href="#/config/application" 
ng-if="Application.current()">here</a>
+               to configure.
+       </span>
+       <span ng-if="!Auth.isRole('ROLE_ADMIN')">Please contact your 
admin.</span>
+</p>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/partials/login.html
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/partials/login.html 
b/eagle-webservice/src/main/webapp/_app/partials/login.html
new file mode 100644
index 0000000..7faef42
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/partials/login.html
@@ -0,0 +1,54 @@
+<!--
+  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="login-box">
+       <div class="login-logo">
+               <a href="#/">Apache Eagle</a>
+       </div>
+
+       <div class="login-box-body" ng-show="!loginSuccess">
+               <p class="login-box-msg">Sign in to start your session</p>
+               <div class="form-group has-feedback">
+                       <input type="text" class="form-control" 
placeholder="User Name" ng-model="username" ng-keypress="login($event)" 
autocomplete="off" id="username">
+                       <span class="glyphicon glyphicon-user 
form-control-feedback"></span>
+               </div>
+               <div class="form-group has-feedback">
+                       <input type="password" class="form-control" 
placeholder="Password" ng-model="password" ng-keypress="login($event)">
+                       <span class="glyphicon glyphicon-lock 
form-control-feedback"></span>
+               </div>
+               <div class="row">
+                       <div class="col-xs-8">
+                               <div class="checkbox">
+                                       <label> <input type="checkbox" 
ng-checked="rememberUser" ng-click="rememberUser = !rememberUser;" /> Remember 
Me
+                                       </label>
+                               </div>
+                       </div>
+                       <div class="col-xs-4">
+                               <button class="btn btn-primary btn-block 
btn-flat" ng-click="login($event, true)" ng-disabled="lock">Sign In</button>
+                       </div>
+               </div>
+       </div>
+
+       <div class="login-box-body text-center" ng-show="loginSuccess">
+               <p class="login-box-msg">Login success</p>
+               <p>
+                       <span class="fa fa-refresh fa-spin"></span>
+                       Loading environment...
+               </p>
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/public/css/animation.css
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/public/css/animation.css 
b/eagle-webservice/src/main/webapp/_app/public/css/animation.css
new file mode 100644
index 0000000..954bd29
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/public/css/animation.css
@@ -0,0 +1,46 @@
+@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.
+ */
+
+[ui-view].ng-enter, [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;
+}
+
+[ui-view].ng-enter {
+       opacity: 0;
+}
+
+[ui-view].ng-enter-active {
+       opacity: 1;
+}
+
+[ui-view].ng-leave {
+       opacity: 1;
+       transform:translate3d(0, 0, 0);
+}
+
+[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-webservice/src/main/webapp/_app/public/css/main.css
----------------------------------------------------------------------
diff --git a/eagle-webservice/src/main/webapp/_app/public/css/main.css 
b/eagle-webservice/src/main/webapp/_app/public/css/main.css
new file mode 100644
index 0000000..a7eba4b
--- /dev/null
+++ b/eagle-webservice/src/main/webapp/_app/public/css/main.css
@@ -0,0 +1,805 @@
+@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.
+ */
+
+/* Frame */
+body.no-sidebar .content-wrapper {
+       margin-left: 0;
+
+       -webkit-transition: none;
+       -moz-transition: none;
+       -o-transition: none;
+       transition: none;
+}
+
+body.no-sidebar .main-footer {
+       margin-left: 0;
+}
+
+/* Navigation */
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header .img-circle {
+       display: inline-block;
+       border: 3px solid;
+       border-color: rgba(255,255,255,0.2);
+       width: 90px;
+       height: 90px;
+       margin-top: 10px;
+}
+
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header .fa {
+       font-size: 60px;
+       color: rgba(255,255,255,0.8);
+       margin-top: 10px;
+}
+
+       /* Common */
+a {
+       cursor: pointer;
+}
+
+/* Table */
+.table.table-sm>tbody>tr>td,
+.table.table-sm>tbody>tr>th,
+.table.table-sm>tfoot>tr>td,
+.table.table-sm>tfoot>tr>th,
+.table.table-sm>thead>tr>td,
+.table.table-sm>thead>tr>th{
+       padding: 3px 8px;
+}
+
+.table thead th .fa.fa-sort,
+.table thead th .fa.fa-sort-asc,
+.table thead th .fa.fa-sort-desc {
+       margin-top: 5px;
+       opacity: 0.3;
+       float: right;
+}
+.table thead th:hover .fa.fa-sort,
+.table thead th:hover .fa.fa-sort-asc,
+.table thead th:hover .fa.fa-sort-desc {
+       opacity: 0.8;
+}
+
+.table tr th,
+.table tr td {
+       -webkit-transition: background .5s linear;
+       -o-transition: background .5s linear;
+       transition: background .5s linear;
+}
+
+.sortTable-cntr .pagination {
+       margin-top: 0;
+}
+
+.table th.input-field,
+.table td.input-field {
+       padding: 0;
+       vertical-align: middle;
+}
+
+.table th.input-field > input,
+.table td.input-field > input,
+.table th.input-field > select,
+.table td.input-field > select {
+       border: none;
+       transition: border-color 0s;
+}
+
+.table th.input-field > input:focus,
+.table td.input-field > input:focus,
+.table th.input-field > select:focus,
+.table td.input-field > select:focus {
+       box-shadow: inset 1px 1px 0px #3c8dbc, inset -1px -1px 0px #3c8dbc;
+}
+
+.table th.input-field > input.has-warning,
+.table td.input-field > input.has-warning {
+       box-shadow: inset 1px 1px 0px #f39c12, inset -1px -1px 0px #f39c12;
+}
+
+/* Box */
+.small-box > a.inner {
+       color: #FFF;
+       display: block;
+}
+
+.small-box > a.inner h3 {
+       overflow: hidden;
+       white-space: nowrap;
+       text-overflow: ellipsis;
+       font-size: 32px;
+}
+
+.info-box.bg-gray,
+.info-box a {
+       color: #FFFFFF;
+}
+.info-box a:hover {
+       color: #FFFFFF;
+       text-decoration: underline;
+}
+
+.info-box-content a.config {
+       color: rgba(255,255,255,0.8);
+}
+.info-box-content a.config:hover {
+       color: #FFFFFF;
+}
+
+.info-box-content.box-clickable {
+       box-shadow: 0 0 3px;
+}
+.box-clickable {
+       cursor: pointer;
+}
+
+.info-box-content .info-box-text.text-large {
+       font-size: 26px;
+       margin: 5px 0 10px 0;
+}
+
+/* inline group */
+.inline-group dl,
+.inline-group dl dt,
+.inline-group dl dd {
+       display: inline-block;
+}
+
+.inline-group dl {
+       margin-right: 35px;
+}
+.inline-group dl dt {
+       margin-right: 20px;
+}
+
+.inline-group.form-inline {
+       margin-top: 5px;
+}
+.inline-group dl {
+       margin-right: 25px;
+}
+.inline-group dl dt {
+       margin-right: 5px;
+}
+
+/* Search box */
+.search-box {
+       position: relative;
+       margin-bottom: 15px;
+}
+.search-box input[type="search"] {
+       padding-left: 26px;
+}
+.search-box .fa.fa-search {
+       position: absolute;
+       top: 8px;
+       left: 8px;
+       z-index: 2;
+       pointer-events: none;
+       color: #999;
+}
+
+/* Navigation Tab */
+ul.nav.nav-tabs li .btn {
+       margin-top: 1px;
+}
+
+.modal-body ul.nav.nav-tabs {
+       border-bottom-color: #F4F4F4;
+       margin-bottom: 15px;
+}
+
+.modal-body ul.nav.nav-tabs li {
+       border-top: 3px solid #FFFFFF;
+       margin-right: 3px;
+}
+.modal-body ul.nav.nav-tabs li.active {
+       border-top-color: #3c8dbc;
+}
+
+.modal-body ul.nav.nav-tabs li > a,
+.modal-body ul.nav.nav-tabs li > a:active,
+.modal-body ul.nav.nav-tabs li > a:hover {
+       border: none;
+       border-radius: 0;
+       margin: 0;
+       padding: 6px 15px 8px 15px;
+       color: #444;
+}
+.modal-body ul.nav.nav-tabs li:not(.active) > a:hover {
+       background: rgba(0,0,0,0);
+       color: #999;
+}
+.modal-body ul.nav.nav-tabs li.active > a {
+       border-left: 1px solid #F4F4F4;
+       border-right: 1px solid #F4F4F4;
+}
+
+/* Step Navigation */
+.step-cntr .step {
+       background: #3c8dbc;
+       margin: 0 0 20px 0;
+       color: #FFF;
+       height: 60px;
+       border-radius: 3px;
+       box-shadow: 0 1px 1px rgba(0,0,0,0.1);
+       display: block;
+
+       -webkit-transition: background .15s linear;
+       -o-transition: background .15s linear;
+       transition: background .15s linear;
+}
+.step-cntr .step.active {
+       background: #f39c12;
+}
+
+.step-cntr .step h1,
+.step-cntr .step h2,
+.step-cntr .step p {
+       margin: 0;
+       padding: 0;
+       overflow: hidden;
+       white-space: nowrap;
+       text-overflow: ellipsis;
+}
+
+.step-cntr .step h1 {
+       display: inline-block;
+       font-size: 30px;
+       float: left;
+       border-right: 2px solid rgba(255,255,255,0.2);
+       width: 60px;
+       height: 60px;
+       text-align: center;
+       padding-top: 12px;
+       margin-right: 10px;
+}
+.step-cntr .step h2 {
+       font-size: 18px;
+       padding: 8px 0 5px 0;
+}
+
+/* Panel */
+.panel-group.panel-group-sm .panel .panel-heading {
+       padding: 5px 6px 5px 10px;
+}
+.panel-group.panel-group-sm .panel .panel-heading h4 {
+       font-size: 14px;
+}
+.panel-group.panel-group-sm .panel .panel-heading h4 a {
+       display: block;
+}
+.panel-group.panel-group-sm .panel .panel-heading .pull-right {
+       padding-left: 5px;
+       padding-right: 5px;
+       border-radius: 3px;
+}
+
+/* Drop Down */
+.dropdown-menu > li.danger > a {
+       color: #dd4b39;
+}
+.dropdown-menu > li.danger > a:hover {
+       color: #FFFFFF;
+       background: #dd4b39;
+}
+
+/* Drop Down */
+.dropdown-menu.left {
+       right: 0;
+       left: auto;
+}
+
+.dropdown-submenu{position:relative;}
+.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0
 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
+.dropdown-submenu:hover>.dropdown-menu{display:block;}
+.dropdown-submenu>a:after{display:block;content:" 
";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px
 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
+.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
+.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px
 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
+
+/* Input Group */
+.input-group .input-group-btn select {
+       width: auto;
+}
+
+/* Form group */
+.form-group .checkbox {
+       display: inline;
+       margin-right: 10px;
+}
+
+.form-group select.has-warning,
+.form-group input.has-warning {
+       border-color: #f39c12;
+       box-shadow: none;
+}
+
+.checkbox.noMargin {
+       margin-top: 0;
+       margin-bottom: 5px;
+}
+
+/* UL */
+ul.path {
+       margin-left: 0;
+}
+
+ul.path li {
+       padding: 0;
+       margin-right: 5px;
+}
+ul.path li a {
+       color: #FFFFFF;
+}
+
+ul.tree {
+       padding: 0 0 0 5px;
+}
+
+ul.tree > li,
+ul.tree > li > ul > li {
+       list-style-type: none;
+}
+
+ul.tree .tree-item .hover {
+       display: none;
+}
+ul.tree .tree-item:hover .hover {
+       display: inline-block;
+}
+
+ul.tree > li > ul {
+       padding: 0 0 0 25px;
+}
+
+ul.tree > li > ul > li.active {
+       background: #F4F4F4;
+}
+
+ul.tree.tree-bordered {
+       border: 1px solid #f4f4f4;
+}
+ul.tree.tree-bordered,
+ul.tree.tree-bordered > li > ul {
+       padding: 0;
+}
+ul.tree.tree-bordered > li:not(:last-child) {
+       border-bottom: 1px solid #f4f4f4;
+}
+ul.tree.tree-bordered > li > ul > li {
+       border-top: 1px solid #f4f4f4;
+}
+ul.tree.tree-bordered > li > span,
+ul.tree.tree-bordered > li > a {
+       display: block;
+       padding: 8px;
+}
+ul.tree.tree-bordered > li > ul > li > span,
+ul.tree.tree-bordered > li > ul > li > a {
+       display: block;
+       padding: 8px 8px 8px 30px;
+}
+
+.product-list-in-box > .item {
+       -webkit-transition: background .5s linear;
+       -o-transition: background .5s linear;
+       transition: background .5s linear;
+}
+.product-list-in-box > .item.ng-animate {
+       transition: 0s;
+}
+.product-list-in-box > .item.active {
+       background: #F5FAFC;
+       -webkit-transition: none;
+       -o-transition: none;
+       transition: none;
+}
+
+.nav.fixed-height,
+.products-list.fixed-height {
+       height: 402px;
+       overflow-y: auto;
+}
+
+.products-list .product-operation {
+       float: left;
+       border: 1px solid #9EC8E0;
+       border-radius: 5px;
+       overflow: hidden;
+}
+
+.products-list .product-operation .fa {
+       display: block;
+       padding: 4px 16px;
+       color: #3c8dbc;
+}
+.products-list .product-operation a.fa:hover {
+       color: #FFFFFF;
+       background: #337ab7;
+}
+
+.products-list .product-operation.single .fa {
+       padding: 12px 12px;
+       font-size: 20px;
+}
+
+.products-list .item .product-info a.fa.fa-times {
+       display: none;
+}
+.products-list .item:hover .product-info a.fa.fa-times {
+       display: block;
+}
+
+/* Label */
+.label.label-default {
+       color: #FFFFFF;
+}
+
+.label.label-sm {
+       padding: .0em .4em .1em;
+}
+
+/* Row */
+.row.narrow {
+       margin-left: -5px;
+       margin-right: -5px;
+       margin-bottom: -10px;
+}
+
+.row.narrow>.col-xs-1, .row.narrow>.col-sm-1, .row.narrow>.col-md-1, 
.row.narrow>.col-lg-1, .row.narrow>.col-xs-2, .row.narrow>.col-sm-2, 
.row.narrow>.col-md-2, .row.narrow>.col-lg-2, .row.narrow>.col-xs-3, 
.row.narrow>.col-sm-3, .row.narrow>.col-md-3, .row.narrow>.col-lg-3, 
.row.narrow>.col-xs-4, .row.narrow>.col-sm-4, .row.narrow>.col-md-4, 
.row.narrow>.col-lg-4, .row.narrow>.col-xs-5, .row.narrow>.col-sm-5, 
.row.narrow>.col-md-5, .row.narrow>.col-lg-5, .row.narrow>.col-xs-6, 
.row.narrow>.col-sm-6, .row.narrow>.col-md-6, .row.narrow>.col-lg-6, 
.row.narrow>.col-xs-7, .row.narrow>.col-sm-7, .row.narrow>.col-md-7, 
.row.narrow>.col-lg-7, .row.narrow>.col-xs-8, .row.narrow>.col-sm-8, 
.row.narrow>.col-md-8, .row.narrow>.col-lg-8, .row.narrow>.col-xs-9, 
.row.narrow>.col-sm-9, .row.narrow>.col-md-9, .row.narrow>.col-lg-9, 
.row.narrow>.col-xs-10, .row.narrow>.col-sm-10, .row.narrow>.col-md-10, 
.row.narrow>.col-lg-10, .row.narrow>.col-xs-11, .row.narrow>.col-sm-11, 
.row.narrow>.col-md-11, .
 row.narrow>.col-lg-11, .row.narrow>.col-xs-12, .row.narrow>.col-sm-12, 
.row.narrow>.col-md-12, .row.narrow>.col-lg-12 {
+       padding-left: 5px;
+       padding-right: 5px;
+}
+
+.row.narrow > [class^="col-"],
+.row.narrow > [class*=" col-"] {
+       margin-bottom: 10px;
+}
+
+/* Chart */
+.sortable-mock-element .nvd3-chart-wrapper {
+       background: #FFFFFF;
+       opacity: 0.8;
+}
+
+.sortable-enter .nvd3-chart-wrapper {
+       border-color: #3c8dbc;
+       pointer-events: none;
+}
+.sortable-enter .nvd3-chart-wrapper .nvtooltip {
+       display: none;
+}
+
+.nvd3-chart-wrapper {
+       position: relative;
+       border: 1px solid rgba(0,0,0,0.1);
+}
+.nvd3-chart-wrapper:hover {
+       //border-color: #F4F4F4;
+}
+
+.nvd3-chart-wrapper .nvd3-chart-config {
+       position: absolute;
+       top: 1px;
+       right: 1px;
+       display: none;
+       border-radius: 0;
+       padding: 0 5px;
+       background: rgba(0,0,0,0.7);
+}
+.nvd3-chart-wrapper:hover .nvd3-chart-config {
+       display: block;
+}
+
+.nvd3-chart-wrapper .nvd3-chart-config a {
+       color: rgba(255,255,255, 0.9);
+       padding: 5px 2px 4px 2px;
+       font-size: 16px;
+}
+.nvd3-chart-wrapper .nvd3-chart-config a:hover {
+       color: #FFFFFF;
+}
+
+.nvd3-chart-cntr {
+       padding: 5px;
+}
+
+.nvd3-chart-cntr > h3 {
+       text-align: center;
+       font-size: 16px;
+       font-weight: bolder;
+       margin: 0;
+       padding: 5px 0;
+
+       overflow:hidden;
+       text-overflow:ellipsis;
+
+}
+
+.nvd3-chart-cntr > svg.nvd3-svg {
+       height: 200px;
+}
+
+.nvd3-chart-cntr.lg > svg.nvd3-svg {
+       height: 400px;
+}
+
+/* Tab */
+body .tab-content>.tab-pane {
+       display: block;
+       height: 0px;
+       overflow: hidden;
+       position: relative;
+}
+body .tab-content>.tab-pane.active {
+       height: auto;
+       overflow-x: visible;
+       overflow-y: visible;
+}
+
+body .modal-body .nav-pills > li > a,
+body .box-body .nav-pills > li > a {
+       padding: 5px 15px;
+       border: none;
+}
+
+body .modal-body .nav-stacked > li {
+       border-bottom: 1px solid #f4f4f4;
+       margin: 0;
+}
+body .modal-body .nav-stacked > li:last-child {
+       border-bottom: none;
+}
+
+body .box-body .nav-tabs-custom {
+       box-shadow: none;
+       margin-bottom: 0;
+}
+body .box-body .nav-tabs-custom > .nav-tabs > li:first-of-type.active > a {
+       border-left-color: #f4f4f4;
+}
+body .box-body .nav-tabs-custom > .nav-tabs > li > a {
+       padding: 8px 15px;
+}
+body .box-body .nav-tabs-custom > .tab-content {
+       padding: 10px 0;
+}
+
+/* Box */
+.box .guideline {
+       margin-top: 0;
+}
+
+.box.inner-box {
+       border: none;
+       box-shadow: none;
+       padding: 5px 10px;
+       margin: 0;
+       border-bottom: 1px solid #f4f4f4;
+       position: relative;
+       border-radius: 0;
+}
+
+.box.inner-box .box-title {
+       margin: 0 5px 5px 0;
+       padding: 0;
+       font-size: 16px;
+       font-weight: bolder;
+       display: inline-block;
+       word-break: break-all;
+}
+
+.box.inner-box .box-tools {
+       position: absolute;
+       top: 0;
+       right: 0;
+}
+
+.box.inner-box:last-child {
+       border-bottom: none;
+}
+
+/* Navigation Tab */
+.nav-tabs-custom {
+       position: relative;
+}
+
+.nav-tabs-custom .box-tools {
+       position: absolute;
+       right: 15px;
+       top: 8px;
+}
+
+.nav-tabs-custom .box-tools .strong {
+       font-weight: bolder;
+}
+
+/* Customize */
+#content {
+       position: relative;
+}
+
+.page-fixed {
+       position: absolute;
+       top: -45px;
+       right: 0;
+}
+
+@media (max-width:991px) {
+       .page-fixed {
+               top: -70px;
+       }
+}
+
+.fixed-right {
+       position: absolute;
+       right: 0;
+       z-index: 3;
+}
+
+.main-header .logo img {
+       height: 34px;
+}
+
+.main-header .navbar-toggle {
+       float: none;
+       border-radius: 0;
+}
+.main-header .navbar-toggle:hover {
+       background: rgba(0, 0, 0, 0.1);
+}
+
+#moduleMenu > ul > li.active > a {
+       border-top: 3px solid rgba(255,255,255,0.8);
+       padding-top: 12px;
+}
+
+@media (max-width: 767px) {
+       #moduleMenu > ul > li.active > a {
+               padding: 10px 15px;
+               border-top: none;
+               border-left: 3px solid rgba(255,255,255,0.8);
+       }
+
+       .main-header .navbar .navbar-custom-menu .nav .dropdown-menu li a {
+               color: #333;
+       }
+       .main-header .navbar .navbar-custom-menu .nav .dropdown-menu li a:hover 
{
+               color: #FFF;
+       }
+}
+
+#timeRangePickerCntr .navbar-form {
+       display: inline-block;
+       padding-right: 0;
+}
+
+#timeRangePickerCntr #timeRangePicker {
+       min-width: 300px;
+}
+
+body .login-box, body .register-box {
+       margin: 3% auto;
+}
+
+.content-header > .breadcrumb > li {
+       font-size: 14px;
+}
+
+.daterangepicker .ranges {
+  width: 110px!important;
+}
+.daterangepicker .daterangepicker_start_input,
+.daterangepicker .daterangepicker_end_input {
+       display: block!important;
+       padding: 0!important;
+       float: none!important;
+}
+.daterangepicker .daterangepicker_start_input .input-mini,
+.daterangepicker .daterangepicker_end_input .input-mini {
+       width: 110px!important;
+}
+
+.form-group.inner-icon {
+       position: relative;
+}
+.form-group.inner-icon .fa {
+       position: absolute;
+       left: 10px;
+       top: 10px;
+}
+.form-group.inner-icon input {
+       padding-left: 35px;
+}
+
+#autoRefreshCntr > a {
+       border: none;
+       opacity: 0.3;
+}
+#autoRefreshCntr.autoRefresh > a {
+       opacity: 1;
+}
+
+.table-responsive .row {
+       margin: 0;
+}
+
+
+/* Misc */
+body .tooltip-inner {
+       max-width: 500px;
+}
+
+.text-nowrap {
+       white-space: nowrap;
+}
+
+.text-ellipsis,
+.label.text-ellipsis {
+       overflow:hidden;
+       text-overflow:ellipsis;
+       display: inline-block;
+       white-space: nowrap;
+       max-width: 100%;
+}
+td.text-ellipsis {
+       display: table-cell;
+}
+
+.text-breakall {
+       max-width: 100%;
+       display: inline-block;
+       word-wrap: break-word;
+}
+
+.btn.btn-xs.sm {
+       font-size: 12px;
+       padding: 2px 6px;
+}
+
+.form-control.input-xs {
+       height: 24px;
+       padding: 2px 8px;
+       font-size: 12px;
+       line-height: 100%;
+}
+
+pre.noWrap {
+       border: none;
+       border-radius: 0;
+       background: transparent;
+       margin: 0;
+       padding: 0;
+}
+
+.noSelect {
+       -khtml-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+}
+
+.blink {
+       animation: blinker 1s linear infinite;
+}
+
+@keyframes blinker {
+       50% {opacity: 0.0;}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/public/feature/classification/controller.js
----------------------------------------------------------------------
diff --git 
a/eagle-webservice/src/main/webapp/_app/public/feature/classification/controller.js
 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/controller.js
new file mode 100644
index 0000000..462b41b
--- /dev/null
+++ 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/controller.js
@@ -0,0 +1,358 @@
+/*
+ * 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("classification");
+       var eagleApp = angular.module('eagleApp');
+
+       // ==============================================================
+       // =                          Function                          =
+       // ==============================================================
+
+       // =============================================================
+       // =                        Sensitivity                        =
+       // =============================================================
+       feature.navItem("sensitivity", "Classification", "user-secret");
+       feature.controller('sensitivity', function(PageConfig, Site, $scope, 
Application, Entities, UI) {
+               PageConfig.pageTitle = "Data Classification";
+               PageConfig.pageSubTitle = Site.current().tags.site;
+               $scope.ajaxId = eagleApp._TRS();
+               $scope.viewConfig = Application.current().configObj.view;
+
+               if(!$scope.viewConfig) {
+                       $.dialog({
+                               title: "OPS",
+                               content: "View configuration not defined in 
Application."
+                       });
+                       return;
+               }
+
+               // ===================== Function =====================
+               $scope.export = function() {
+                       var _data = {};
+                       UI.fieldConfirm({title: "Export Classification", 
confirm: false, size: "large"}, _data, [
+                               {name: "Data", field: "data", type: "blob", 
rows: 20, optional: true, readonly: true}]
+                       );
+
+                       Entities.queryEntities($scope.viewConfig.service, 
{site: Site.current().tags.site})._promise.then(function(data) {
+                               _data.data = JSON.stringify(data, null, "\t");
+                       });
+               };
+
+               $scope.import = function() {
+                       UI.fieldConfirm({title: "Import Classification", size: 
"large"}, {}, [
+                               {name: "Data", field: "data", type: "blob", 
rows: 20, optional: true}
+                       ], function(entity) {
+                               var _list = common.parseJSON(entity.data, 
false);
+                               if(!_list) {
+                                       return "Invalid JSON format";
+                               }
+                               if(!$.isArray(_list)) {
+                                       return "Not an array";
+                               }
+                       }).then(null, null, function(holder) {
+                               
Entities.updateEntity($scope.viewConfig.service, 
common.parseJSON(holder.entity.data, []), {timestamp: 
false})._promise.then(function() {
+                                       holder.closeFunc();
+                                       location.reload();
+                               });
+                       });
+               };
+
+               $scope.deleteAll = function() {
+                       UI.deleteConfirm("All the Classification 
Data").then(null, null, function(holder) {
+                               
Entities.deleteEntities($scope.viewConfig.service, {site: 
Site.current().tags.site})._promise.then(function() {
+                                       holder.closeFunc();
+                                       location.reload();
+                               });
+                       });
+               };
+       });
+     // =============================================================
+       // =                    Sensitivity - Job                   =
+       // =============================================================
+       feature.controller('sensitivityViewJob', function(Site, $scope, 
$wrapState, Entities) {
+               $scope.items = [];
+
+               // Mark sensitivity
+               $scope._oriItem = {};
+               $scope._markItem = {};
+
+               // ======================= View =======================
+               // Item
+               $scope.updateItems = function() {
+                       $scope.items = Entities.query($scope.viewConfig.api, 
{site: Site.current().tags.site});
+               };
+
+
+               $scope.updateItems();
+
+               // =================== Sensitivity ===================
+               $scope.markSensitivity = function(item) {
+                       $scope._oriItem = item;
+                       $scope._markItem = {
+                               prefix: $scope.viewConfig.prefix,
+                               tags: {
+                                       site: Site.current().tags.site
+                               },
+                               sensitivityType: ""
+                       };
+
+                       $scope._markItem.tags[$scope.viewConfig.keys[0]] = 
item.jobId;
+                       $("#sensitivityMDL").modal();
+               };
+               $scope.confirmUpateSensitivity = function() {
+                       $scope._oriItem.sensitiveType = 
$scope._markItem.sensitivityType;
+                       Entities.updateEntity($scope.viewConfig.service, 
$scope._markItem, {timestamp: false})._promise.success(function(data) {
+                               Entities.dialog(data);
+                       });
+                       $("#sensitivityMDL").modal('hide');
+               };
+               $scope.unmarkSensitivity = function(item) {
+                       $.dialog({
+                               title: "Unmark Confirm",
+                               content: "Do you want to remove the sensitivity 
mark on '" + item.jobId + "'?",
+                               confirm: true
+                       }, function(ret) {
+                               if(!ret) return;
+
+                               var _cond = {site: Site.current().tags.site};
+                               _cond[$scope.viewConfig.keys[0]] = item.jobId;
+                               
Entities.deleteEntities($scope.viewConfig.service, _cond);
+
+                               item.sensitiveType = null;
+                               $scope.$apply();
+                       });
+               };
+       });
+       // =============================================================
+       // =                    Sensitivity - Folder                   =
+       // =============================================================
+       feature.controller('sensitivityViewFolder', function(Site, $scope, 
$wrapState, Entities) {
+               $scope.path = $wrapState.param.path || "/";
+               $scope.pathUnitList = [];
+               $scope.items = [];
+
+               // Mark sensitivity
+               $scope._oriItem = {};
+               $scope._markItem = {};
+
+               // ======================= View =======================
+               // Path
+               function _refreshPathUnitList(_path) {
+                       var _start,_current, _unitList = [];
+                       _path = _path + (_path.match(/\/$/) ? "" : "/");
+                       for(_current = _start = 0 ; _current < _path.length ; 
_current += 1) {
+                               if(_path[_current] === "/") {
+                                       _unitList.push({
+                                               name: _path.substring(_start, 
_current + (_current === 0 ? 1 : 0)),
+                                               path: _path.substring(0, 
_current === 0 ? 1 : _current)
+                                       });
+                                       _start = _current + 1;
+                               }
+                       }
+                       $scope.pathUnitList = _unitList;
+               }
+
+               // Item
+               $scope.updateItems = function(path) {
+                       if(path) $scope.path = path;
+
+                       $scope.items = Entities.query($scope.viewConfig.api, 
{site: Site.current().tags.site, path: $scope.path});
+                       $scope.items._promise.success(function(data) {
+                               Entities.dialog(data, function() {
+                                       if($scope.path !== "/") 
$scope.updateItems("/");
+                               });
+                       });
+                       _refreshPathUnitList($scope.path);
+               };
+
+               $scope.getFileName = function(item) {
+                       return (item.resource + "").replace(/^.*\//, "");
+               };
+
+               $scope.updateItems($scope.path);
+
+               // =================== Sensitivity ===================
+               $scope.markSensitivity = function(item) {
+                       $scope._oriItem = item;
+                       $scope._markItem = {
+                               prefix: $scope.viewConfig.prefix,
+                               tags: {
+                                       site: Site.current().tags.site
+                               },
+                               sensitivityType: ""
+                       };
+                       $scope._markItem.tags[$scope.viewConfig.keys[0]] = 
item.resource;
+                       $("#sensitivityMDL").modal();
+               };
+               $scope.confirmUpateSensitivity = function() {
+                       $scope._oriItem.sensitiveType = 
$scope._markItem.sensitivityType;
+                       Entities.updateEntity($scope.viewConfig.service, 
$scope._markItem, {timestamp: false})._promise.success(function(data) {
+                               Entities.dialog(data);
+                       });
+                       $("#sensitivityMDL").modal('hide');
+               };
+               $scope.unmarkSensitivity = function(item) {
+                       $.dialog({
+                               title: "Unmark Confirm",
+                               content: "Do you want to remove the sensitivity 
mark on '" + item.resource + "'?",
+                               confirm: true
+                       }, function(ret) {
+                               if(!ret) return;
+
+                               var _cond = {site: Site.current().tags.site};
+                               _cond[$scope.viewConfig.keys[0]] = 
item.resource;
+                               
Entities.deleteEntities($scope.viewConfig.service, _cond);
+
+                               item.sensitiveType = null;
+                               $scope.$apply();
+                       });
+               };
+       });
+
+       // =============================================================
+       // =                    Sensitivity - Table                    =
+       // =============================================================
+       feature.controller('sensitivityViewTable', function(Site, $scope, 
Entities) {
+               $scope.databases = null;
+               $scope.table = null;
+
+               // Mark sensitivity
+               $scope._oriItem = {};
+               $scope._markItem = {};
+
+               // ======================= View =======================
+               var _fillAttr = function(list, key, target) {
+                       list._promise.then(function() {
+                               $.each(list, function(i, unit) {
+                                       unit[key] = unit[target];
+                               });
+                       });
+                       return list._promise;
+               };
+
+               $scope.loadDatabases = function(database) {
+                       var _dbs = 
Entities.query($scope.viewConfig.api.database, {site: 
Site.current().tags.site});
+                       return _fillAttr(_dbs, "database", 
$scope.viewConfig.mapping.database).then(function() {
+                               if($scope.databases) {
+                                       $.each($scope.databases, function(i, 
oriDB) {
+                                               var db = 
common.array.find(oriDB.resource, _dbs, "resource");
+                                               if(db) {
+                                                       db.show = oriDB.show;
+                                                       db.tables = 
oriDB.tables;
+                                               }
+                                       });
+                               }
+                               $scope.databases = _dbs;
+                       });
+               };
+               $scope.loadDatabases();
+
+               $scope.loadTables = function(database, force) {
+                       var _tables, _qry;
+                       if(database.tables && !force) return;
+                       _qry = {
+                               site: Site.current().tags.site
+                       };
+                       _qry[$scope.viewConfig.mapping.database] = 
database[$scope.viewConfig.mapping.database];
+                       _tables = Entities.query($scope.viewConfig.api.table, 
_qry);
+                       if(!database.tables) database.tables = _tables;
+                       _fillAttr(_tables, "table", 
$scope.viewConfig.mapping.table);
+                       return _fillAttr(_tables, "database", 
$scope.viewConfig.mapping.database).then(function() {
+                               database.tables = _tables;
+                       });
+               };
+
+               $scope.loadColumns = function(database, table) {
+                       $scope.table = table;
+
+                       if(table.columns) return;
+                       var _qry = {
+                               site: Site.current().tags.site
+                       };
+                       _qry[$scope.viewConfig.mapping.database] = 
database[$scope.viewConfig.mapping.database];
+                       _qry[$scope.viewConfig.mapping.table] = 
table[$scope.viewConfig.mapping.table];
+                       table.columns = 
Entities.query($scope.viewConfig.api.column, _qry);
+                       _fillAttr(table.columns, "column", 
$scope.viewConfig.mapping.column);
+               };
+
+               $scope.refreshData = function() {
+                       $scope.loadDatabases().then(function() {
+                               if(!$scope.table) return;
+
+                               var _table = $scope.table;
+                               var _db = 
common.array.find($scope.table.database, $scope.databases, "database");
+                               if(_db) {
+                                       $scope.loadTables(_db, 
true).then(function() {
+                                               $scope.table = 
common.array.find(_table.table, _db.tables, "table");
+                                               $scope.table.columns = 
_table.columns;
+                                       });
+                               }
+                       });
+               };
+
+               // =================== Sensitivity ===================
+               $scope.markSensitivity = function(item, event) {
+                       if(event) event.stopPropagation();
+
+                       $scope._oriItem = item;
+                       $scope._markItem = {
+                               prefix: $scope.viewConfig.prefix,
+                               tags: {
+                                       site: Site.current().tags.site
+                               },
+                               sensitivityType: ""
+                       };
+                       $scope._markItem.tags[$scope.viewConfig.keys[0]] = 
item.resource;
+                       $("#sensitivityMDL").modal();
+               };
+               $scope.confirmUpateSensitivity = function() {
+                       $scope._oriItem.sensitiveType = 
$scope._markItem.sensitivityType;
+                       Entities.updateEntity($scope.viewConfig.service, 
$scope._markItem, {timestamp: false})._promise.success(function(data) {
+                               Entities.dialog(data);
+                               $scope.refreshData();
+                       });
+                       $("#sensitivityMDL").modal('hide');
+               };
+               $scope.unmarkSensitivity = function(item, event) {
+                       if(event) event.stopPropagation();
+
+                       $.dialog({
+                               title: "Unmark Confirm",
+                               content: "Do you want to remove the sensitivity 
mark on '" + item.resource + "'?",
+                               confirm: true
+                       }, function(ret) {
+                               if(!ret) return;
+
+                               var _qry = {
+                                       site: Site.current().tags.site
+                               };
+                               _qry[$scope.viewConfig.keys[0]] = item.resource;
+                               
Entities.deleteEntities($scope.viewConfig.service, 
_qry)._promise.then(function() {
+                                       $scope.refreshData();
+                               });
+
+                               item.sensitiveType = null;
+                               $scope.$apply();
+                       });
+               };
+       });
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity.html
----------------------------------------------------------------------
diff --git 
a/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity.html
 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity.html
new file mode 100644
index 0000000..41fb291
--- /dev/null
+++ 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity.html
@@ -0,0 +1,40 @@
+<!--
+  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-primary">
+       <div class="box-header with-border">
+               <i class="fa fa-folder-open"></i>
+               <h3 class="box-title 
ng-binding">{{Application.current().displayName}}</h3>
+               <div class="box-tools pull-right" ng-if="viewConfig">
+                       <div class="btn-group">
+                               <button type="button" class="btn btn-box-tool 
dropdown-toggle" data-toggle="dropdown">
+                                       <span class="fa fa-wrench"></span>
+                               </button>
+                               <ul class="dropdown-menu" role="menu">
+                                       <li><a ng-click="import()"><span 
class="fa fa-cloud-upload"></span> Import</a></li>
+                                       <li><a ng-click="export()"><span 
class="fa fa-cloud-download"></span> Export</a></li>
+                                       <li class="divider"></li>
+                                       <li class="danger"><a 
ng-click="deleteAll()"><span class="fa fa-trash"></span> Delete All</a></li>
+                               </ul>
+                       </div>
+               </div>
+       </div>
+       <div class="box-body">
+               <ng-include ng-if="viewConfig" 
src="'public/feature/classification/page/sensitivity/' + viewConfig.type + 
'.html?_=' + ajaxId"></ng-include>
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/folder.html
----------------------------------------------------------------------
diff --git 
a/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/folder.html
 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/folder.html
new file mode 100644
index 0000000..cfefffa
--- /dev/null
+++ 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/folder.html
@@ -0,0 +1,110 @@
+<!--
+  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 ng-controller="classification_sensitivityViewFolder">
+       <ul class="list-inline path">
+               <li>Path:</li>
+               <li ng-repeat="unit in pathUnitList">
+                       <a ng-click="updateItems(unit.path)" class="label 
bg-black">{{unit.name}}</a>
+               </li>
+       </ul>
+
+       <table class="table table-bordered">
+               <thead>
+                       <tr>
+                               <th width="15%">File Name</th>
+                               <th width="10%">Owner</th>
+                               <th width="10%">Group</th>
+                               <th>Sensitivity Type</th>
+                               <th width="10" 
ng-show="Auth.isRole('ROLE_ADMIN')"> </th>
+                       </tr>
+               </thead>
+               <tbody>
+                       <tr ng-show="items._promise.$$state.status !== 1">
+                               <td colspan="5">
+                                       <span class="fa fa-refresh fa-spin"> 
</span>
+                                       Loading...
+                               </td>
+                       </tr>
+                       <tr ng-show="items._promise.$$state.status === 1 && 
!items.length">
+                               <td colspan="5">
+                                       <span class="fa 
fa-exclamation-triangle"> </span>
+                                       Empty Folder
+                               </td>
+                       </tr>
+                       <tr ng-repeat="item in items" ng-class="{warning : 
item.sensitiveType}">
+                               <td>
+                                       <span ng-show="!item.isdir">
+                                               <span class="fa fa-file"> 
</span>
+                                               {{getFileName(item)}}
+                                       </span>
+                                       <a ng-show="item.isdir" 
ng-click="updateItems(item.resource)">
+                                               <span class="fa fa-folder"> 
</span>
+                                               {{getFileName(item)}}
+                                       </a>
+
+                                       <span class="pull-right" 
ng-show="item.childSensitiveTypes.length">
+                                               <span class="fa fa-dot-circle-o 
text-muted" uib-tooltip="Contain child sensitivity defination"> </span>
+                                       </span>
+                               </td>
+                               <td>{{item.owner}}</td>
+                               <td>{{item.groupName}}</td>
+                               <td>{{item.sensitiveType}}</td>
+                               <td ng-show="Auth.isRole('ROLE_ADMIN')">
+                                       <button class="fa fa-eye btn 
btn-primary btn-xs" ng-click="markSensitivity(item)" 
ng-show="!item.sensitiveType"
+                                       uib-tooltip="Mark as sensitivity data" 
tooltip-animation="false" tooltip-placement="left"> </button>
+                                       <button class="fa fa-eye-slash btn 
btn-warning btn-xs" ng-click="unmarkSensitivity(item)" 
ng-show="item.sensitiveType"
+                                       uib-tooltip="Remove the sensitivity 
mark" tooltip-animation="false" tooltip-placement="left"> </button>
+                               </td>
+                       </tr>
+               </tbody>
+       </table>
+
+
+       <!-- Modal: Create / Edit site -->
+       <div class="modal fade" id="sensitivityMDL" tabindex="-1" role="dialog">
+               <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">Mark 
Sensitivity Data</h4>
+                               </div>
+                               <div class="modal-body">
+                                       <div class="form-group">
+                                               <label>Resource</label>
+                                               <input type="text" 
readonly="readonly" class="form-control" ng-model="_markItem.tags.filedir" />
+                                       </div>
+                                       <div class="form-group">
+                                               <label>* Sensitivity 
Type</label>
+                                               <input type="text" 
class="form-control" ng-model="_markItem.sensitivityType" id="sensitiveType" />
+                                       </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="confirmUpateSensitivity()" 
ng-disabled="!_markItem.sensitivityType">
+                                               Update
+                                       </button>
+                               </div>
+                       </div>
+               </div>
+       </div>
+
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/afb89794/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/job.html
----------------------------------------------------------------------
diff --git 
a/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/job.html
 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/job.html
new file mode 100644
index 0000000..05d70da
--- /dev/null
+++ 
b/eagle-webservice/src/main/webapp/_app/public/feature/classification/page/sensitivity/job.html
@@ -0,0 +1,92 @@
+<!--
+  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 ng-controller="classification_sensitivityViewJob">
+    <ul class="list-inline path">
+        <li>Oozie CoordinatorJob:</li>
+    </ul>
+
+    <table class="table table-bordered">
+        <thead>
+        <tr>
+            <th width="15%">JobId</th>
+            <th width="10%">AppName</th>
+            <th>Sensitivity Type</th>
+            <th width="10" ng-show="Auth.isRole('ROLE_ADMIN')"> </th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-show="items._promise.$$state.status !== 1">
+            <td colspan="5">
+                <span class="fa fa-refresh fa-spin"> </span>
+                Loading...
+            </td>
+        </tr>
+        <tr ng-show="items._promise.$$state.status === 1 && !items.length">
+            <td colspan="5">
+                <span class="fa fa-exclamation-triangle"> </span>
+                Empty
+            </td>
+        </tr>
+        <tr ng-repeat="item in items" ng-class="{warning : 
item.sensitiveType}">
+            <td>{{item.jobId}}</td>
+            <td>{{item.name}}</td>
+            <td>{{item.sensitiveType}}</td>
+            <td ng-show="Auth.isRole('ROLE_ADMIN')">
+                <button class="fa fa-eye btn btn-primary btn-xs" 
ng-click="markSensitivity(item)" ng-show="!item.sensitiveType"
+                        uib-tooltip="Mark as sensitivity data" 
tooltip-animation="false" tooltip-placement="left"> </button>
+                <button class="fa fa-eye-slash btn btn-warning btn-xs" 
ng-click="unmarkSensitivity(item)" ng-show="item.sensitiveType"
+                        uib-tooltip="Remove the sensitivity mark" 
tooltip-animation="false" tooltip-placement="left"> </button>
+            </td>
+        </tr>
+        </tbody>
+    </table>
+
+
+    <!-- Modal: Create / Edit site -->
+    <div class="modal fade" id="sensitivityMDL" tabindex="-1" role="dialog">
+        <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">Mark Sensitivity Data</h4>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label>Resource</label>
+                        <input type="text" readonly="readonly" 
class="form-control" ng-model="_markItem.tags.oozieResource" />
+                    </div>
+                    <div class="form-group">
+                        <label>* Sensitivity Type</label>
+                        <input type="text" class="form-control" 
ng-model="_markItem.sensitivityType" id="sensitiveType" />
+                    </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="confirmUpateSensitivity()" ng-disabled="!_markItem.sensitivityType">
+                        Update
+                    </button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+</div>
\ No newline at end of file

Reply via email to