You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2015/01/31 13:01:43 UTC

[16/50] incubator-kylin git commit: KYLIN-532,refactor front end

KYLIN-532,refactor front end


Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/17817ed1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/17817ed1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/17817ed1

Branch: refs/heads/inverted-index
Commit: 17817ed1a5a332d9defe4fedec388efd7f450c59
Parents: 699269d
Author: jiazhong <ji...@ebay.com>
Authored: Wed Jan 28 16:41:58 2015 +0800
Committer: jiazhong <ji...@ebay.com>
Committed: Wed Jan 28 16:41:58 2015 +0800

----------------------------------------------------------------------
 webapp/app/WEB-INF/kylin-servlet.xml            | 19 ++++
 webapp/app/index.html                           |  5 ++
 webapp/app/js/controllers/auth.js               |  2 +-
 webapp/app/js/controllers/cubeEdit.js           | 93 ++------------------
 webapp/app/js/controllers/cubeModel.js          |  3 +-
 webapp/app/js/controllers/cubes.js              | 11 +--
 webapp/app/js/controllers/job.js                |  6 +-
 webapp/app/js/controllers/page.js               | 67 +++++++-------
 webapp/app/js/controllers/projectMeta.js        |  4 +-
 webapp/app/js/controllers/query.js              |  2 +-
 webapp/app/js/controllers/sourceMeta.js         |  6 +-
 webapp/app/js/filters/filter.js                 |  6 +-
 webapp/app/js/model/cubeConfig.js               | 51 +++++++++++
 webapp/app/js/model/cubeDescModel.js            | 45 ++++++++++
 webapp/app/js/model/projectModel.js             | 46 ++++++++++
 .../cubeDesigner/advanced_settings.html         |  4 +-
 .../app/partials/cubeDesigner/data_model.html   |  2 +-
 .../app/partials/cubeDesigner/incremental.html  |  2 +-
 webapp/app/partials/cubeDesigner/measures.html  | 15 ++--
 webapp/app/partials/cubes/cube_json_edit.html   |  4 +-
 webapp/app/partials/cubes/cubes.html            |  6 +-
 webapp/app/partials/jobs/job_steps.html         |  2 +-
 webapp/app/partials/jobs/jobs.html              |  6 +-
 webapp/app/partials/login.html                  |  4 +-
 webapp/app/partials/query/query.html            |  8 +-
 webapp/app/partials/tables/source_metadata.html |  6 +-
 26 files changed, 260 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/WEB-INF/kylin-servlet.xml
----------------------------------------------------------------------
diff --git a/webapp/app/WEB-INF/kylin-servlet.xml b/webapp/app/WEB-INF/kylin-servlet.xml
new file mode 100644
index 0000000..4a92f88
--- /dev/null
+++ b/webapp/app/WEB-INF/kylin-servlet.xml
@@ -0,0 +1,19 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:mvc="http://www.springframework.org/schema/mvc"
+       xmlns:task="http://www.springframework.org/schema/task"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+    http://www.springframework.org/schema/context
+    http://www.springframework.org/schema/context/spring-context-3.1.xsd
+    http://www.springframework.org/schema/task
+    http://www.springframework.org/schema/task/spring-task-3.1.xsd
+    http://www.springframework.org/schema/mvc
+    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
+
+
+
+
+
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/index.html
----------------------------------------------------------------------
diff --git a/webapp/app/index.html b/webapp/app/index.html
index 124ed52..c270499 100644
--- a/webapp/app/index.html
+++ b/webapp/app/index.html
@@ -106,6 +106,11 @@
 <script src="js/services/tree.js"></script>
 <script src="js/services/users.js"></script>
 <script src="js/services/ngLoading.js"></script>
+
+<script src="js/model/cubeConfig.js"></script>
+<script src="js/model/cubeDescModel.js"></script>
+<script src="js/model/projectModel.js"></script>
+
 <script src="js/controllers/page.js"></script>
 <script src="js/controllers/index.js"></script>
 <script src="js/controllers/access.js"></script>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/auth.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/auth.js b/webapp/app/js/controllers/auth.js
index 4976db6..6ffa2e5 100644
--- a/webapp/app/js/controllers/auth.js
+++ b/webapp/app/js/controllers/auth.js
@@ -10,7 +10,7 @@ KylinApp.controller('LoginCtrl', function ($scope, $rootScope, $location, $base6
         httpHeaders.common['Authorization'] = 'Basic ' + $base64.encode($scope.username + ':' + $scope.password);
         $scope.loading = true;
         //verify project
-        if($scope.project.projects.length&&!$scope.project.selectedProject){
+        if($scope.projectModel.projects.length&&!$scope.projectModel.selectedProject){
             $scope.loading = false;
             $scope.error = "Unable to login, please select a project";
             return;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/cubeEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js
index b8e17e1..8450a5d 100644
--- a/webapp/app/js/controllers/cubeEdit.js
+++ b/webapp/app/js/controllers/cubeEdit.js
@@ -1,55 +1,13 @@
 'use strict';
 
 
-KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $location, $templateCache, $interpolate, MessageService, TableService, CubeDescService, CubeService, loadingRequest, SweetAlert,$log) {
+KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $location, $templateCache, $interpolate, MessageService, TableService, CubeDescService, CubeService, loadingRequest, SweetAlert,$log,cubeConfig,CubeDescModel) {
+    $scope.cubeConfig = cubeConfig;
 
     //add or edit ?
     var absUrl = $location.absUrl();
     $scope.cubeMode = absUrl.indexOf("/cubes/add")!=-1?'addNewCube':absUrl.indexOf("/cubes/edit")!=-1?'editExistCube':'default';
 
-    //~ Define metadata & class
-    $scope.measureParamType = ['column', 'constant'];
-    $scope.measureExpressions = ['SUM', 'MIN', 'MAX', 'COUNT', 'COUNT_DISTINCT'];
-    $scope.dimensionDataTypes = ["string", "tinyint", "int", "bigint", "date"];
-    $scope.cubeCapacities = ["MEDIUM", "SMALL", "LARGE"];
-    $scope.cubePartitionTypes = ['APPEND', 'UPDATE_INSERT'];
-    $scope.joinTypes = [
-        {name: 'Left', value: 'left'},
-        {name: 'Inner', value: 'inner'},
-        {name: 'Right', value: 'right'}
-    ];
-    $scope.queryPriorities = [
-        {name: 'NORMAL', value: 50},
-        {name: 'LOW', value: 70},
-        {name: 'HIGH', value: 30}
-    ];
-    $scope.measureDataTypes = [
-        {name: 'INT', value: 'int'},
-        {name: 'BIGINT', value: 'bigint'},
-        {name: 'DECIMAL', value: 'decimal'},
-        {name: 'DOUBLE', value: 'double'},
-        {name: 'DATE', value: 'date'},
-        {name: 'STRING', value: 'string'}
-    ];
-    $scope.distinctDataTypes = [
-        {name: 'Error Rate < 9.75%', value: 'hllc10'},
-        {name: 'Error Rate < 4.88%', value: 'hllc12'},
-        {name: 'Error Rate < 2.44%', value: 'hllc14'},
-        {name: 'Error Rate < 1.72%', value: 'hllc15'},
-        {name: 'Error Rate < 1.22%', value: 'hllc16'}
-    ];
-
-    $scope.dftSelections = {
-        measureExpression: 'SUM',
-        measureParamType: 'column',
-        measureDataType: {name: 'BIGINT', value: 'bigint'},
-        distinctDataType: {name: 'Error Rate < 2.44%', value: 'hllc14'},
-        cubeCapacity: 'MEDIUM',
-        queryPriority: {name: 'NORMAL', value: 50},
-        cubePartitionType: 'APPEND'
-    };
-
-    $scope.dictionaries = ["true", "false"];
     $scope.srcTablesInProject = [];
 
     $scope.getColumnsByTable = function (name) {
@@ -81,47 +39,6 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
         }
     };
 
-    var CubeMeta = {
-        createNew: function () {
-            var cubeMeta = {
-                "name": "",
-                "description": "",
-                "fact_table": "",
-                "filter_condition": null,
-                "notify_list": [],
-                "cube_partition_desc": {
-                    "partition_date_column": null,
-                    "partition_date_start": null,
-                    "cube_partition_type": 'APPEND'
-                },
-                "capacity": "MEDIUM",
-                "cost": 50,
-                "dimensions": [],
-                "measures": [
-                    {   "id": 1,
-                        "name": "_COUNT_",
-                        "function": {
-                            "expression": "COUNT",
-                            "returntype": "bigint",
-                            "parameter": {
-                                "type": "constant",
-                                "value": "1"
-                            }
-                        }
-                    }
-                ],
-                "rowkey": {
-                    "rowkey_columns": [],
-                    "aggregation_groups": []
-                },
-                "hbase_mapping": {
-                    "column_family": []
-                }
-            };
-
-            return cubeMeta;
-        }
-    };
 
     // ~ Define data
     $scope.state = {
@@ -142,8 +59,8 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
             }
         });
     } else {
-        $scope.cubeMetaFrame = CubeMeta.createNew();
-        $scope.cubeMetaFrame.project = $scope.project.selectedProject;
+        $scope.cubeMetaFrame = CubeDescModel.createNew();
+        $scope.cubeMetaFrame.project = $scope.projectModel.selectedProject;
         $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
     }
 
@@ -535,7 +452,7 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
         });
     }
 
-    $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+    $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
         if(!newValue){
             return;
         }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/cubeModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeModel.js b/webapp/app/js/controllers/cubeModel.js
index be3e32a..c6b597d 100644
--- a/webapp/app/js/controllers/cubeModel.js
+++ b/webapp/app/js/controllers/cubeModel.js
@@ -1,6 +1,7 @@
 'use strict';
 
-KylinApp.controller('CubeModelCtrl', function ($scope, $modal) {
+KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig) {
+    $scope.cubeConfig = cubeConfig;
     var DataModel = function () {
         return {
             name: '',

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/cubes.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubes.js b/webapp/app/js/controllers/cubes.js
index 6648e2d..0964b47 100644
--- a/webapp/app/js/controllers/cubes.js
+++ b/webapp/app/js/controllers/cubes.js
@@ -1,14 +1,15 @@
 'use strict';
 
 KylinApp
-    .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService,  ProjectService,SweetAlert,loadingRequest,$log) {
+    .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService,  ProjectService,SweetAlert,loadingRequest,$log,ProjectModel) {
 
         $scope.listParams={
             cubeName: $routeParams.cubeName,
             projectName: $routeParams.projectName
         };
         if($routeParams.projectName){
-            $scope.project.selectedProject = $routeParams.projectName;
+            $scope.projectModel.selectedProject = $routeParams.projectName;
+            $scope.projectModel.setSelectedProject($routeParams.projectName);
         }
         $scope.cubes = [];
         $scope.loading = false;
@@ -28,7 +29,7 @@ KylinApp
             dimensionFilter: '', measureFilter: ''};
 
         $scope.list = function (offset, limit) {
-            if(!$scope.project.projects.length){
+            if(!$scope.projectModel.projects.length){
                 return [];
             }
             offset = (!!offset) ? offset : 0;
@@ -39,7 +40,7 @@ KylinApp
             if ($scope.listParams.cubeName) {
                 queryParam.cubeName = $scope.listParams.cubeName;
             }
-               queryParam.projectName = $scope.project.selectedProject;
+               queryParam.projectName = $scope.projectModel.selectedProject;
 
             $scope.loading = true;
             CubeService.list(queryParam, function (cubes) {
@@ -70,7 +71,7 @@ KylinApp
             return defer.promise;
         };
 
-        $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+        $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
             if(newValue!=oldValue||newValue==null){
                 $scope.cubes=[];
                 $scope.reload();

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/job.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/job.js b/webapp/app/js/controllers/job.js
index 13cc2ff..6f301bb 100644
--- a/webapp/app/js/controllers/job.js
+++ b/webapp/app/js/controllers/job.js
@@ -34,7 +34,7 @@ KylinApp
 
 
         // projectName from page ctrl
-        $scope.state = {loading: false, refreshing: false, filterAttr: 'last_modified', filterReverse: true, reverseColumn: 'last_modified', projectName:$scope.project.selectedProject};
+        $scope.state = {loading: false, refreshing: false, filterAttr: 'last_modified', filterReverse: true, reverseColumn: 'last_modified', projectName:$scope.projectModel.selectedProject};
 
         ProjectService.list({}, function (projects) {
             angular.forEach(projects, function(project, index){
@@ -43,7 +43,7 @@ KylinApp
         });
 
         $scope.list = function (offset, limit) {
-            if(!$scope.project.projects.length){
+            if(!$scope.projectModel.projects.length){
                 return [];
             }
             offset = (!!offset) ? offset : 0;
@@ -95,7 +95,7 @@ KylinApp
         };
 
 
-        $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+        $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
             if(newValue!=oldValue||newValue==null){
                 $scope.jobs={};
                 $scope.state.projectName = newValue;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/page.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/page.js b/webapp/app/js/controllers/page.js
index 82bb878..a574075 100644
--- a/webapp/app/js/controllers/page.js
+++ b/webapp/app/js/controllers/page.js
@@ -1,6 +1,6 @@
 'use strict';
 
-KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $location, $rootScope, $routeParams, $http, UserService,ProjectService,SweetAlert,$cookieStore,$log, kylinConfig) {
+KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $location, $rootScope, $routeParams, $http, UserService,ProjectService,SweetAlert,$cookieStore,$log, kylinConfig,ProjectModel) {
 
     //init kylinConfig to get kylin.Propeties
     kylinConfig.init();
@@ -22,6 +22,30 @@ KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $loc
     $scope.angular = angular;
     $scope.userService = UserService;
     $scope.activeTab = "";
+    $scope.projectModel = ProjectModel;
+
+    //init
+    ProjectService.list({}, function (projects) {
+        var _projects = [];
+        angular.forEach(projects, function(project, index){
+            _projects.push(project.name);
+        });
+        _projects = _.sortBy(_projects, function (i) { return i.toLowerCase(); });
+
+        ProjectModel.setProjects(_projects);
+
+        var absUrl = $location.absUrl();
+
+        var projectInCookie = $cookieStore.get("project");
+        if(absUrl.indexOf("/login")==-1){
+            var selectedProject=projectInCookie!=null?projectInCookie:null;
+            $scope.projectModel.setSelectedProject(selectedProject);
+        }else{
+            var selectedProject=$scope.projectModel.selectedProject!=null?$scope.projectModel.selectedProject:projectInCookie!=null?projectInCookie:$scope.projectModel.projects[0];
+            $scope.projectModel.setSelectedProject(selectedProject);
+        }
+    });
+
 
     // Set up common methods
     $scope.logout = function () {
@@ -120,29 +144,6 @@ KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $loc
     };
 
 
-
-    $scope.project = {
-        projects:[],
-        selectedProject: null
-    };
-
-
-    ProjectService.list({}, function (projects) {
-        angular.forEach(projects, function(project, index){
-            $scope.project.projects.push(project.name);
-        });
-        $scope.project.projects = _.sortBy($scope.project.projects, function (i) { return i.toLowerCase(); });
-
-        var absUrl = $location.absUrl();
-
-        var projectInCookie = $cookieStore.get("project");
-        if(absUrl.indexOf("/login")==-1){
-            $scope.project.selectedProject=projectInCookie!=null?projectInCookie:null;
-        }else{
-            $scope.project.selectedProject=$scope.project.selectedProject!=null?$scope.project.selectedProject:projectInCookie!=null?projectInCookie:$scope.project.projects[0];
-        }
-    });
-
     $scope.toCreateProj = function () {
         $modal.open({
             templateUrl: 'project.html',
@@ -159,10 +160,10 @@ KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $loc
     };
 
 
-    $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+    $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
         if(newValue!=oldValue){
             $log.log("project updated in page controller,from:"+oldValue+" To:"+newValue);
-            $cookieStore.put("project",$scope.project.selectedProject);
+            $cookieStore.put("project",$scope.projectModel.selectedProject);
         }
 
     });
@@ -183,11 +184,9 @@ KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $loc
         }
     };
 
-
-
 });
 
-var projCtrl = function ($scope, $modalInstance, ProjectService, MessageService, projects, project,SweetAlert) {
+var projCtrl = function ($scope,$location, $modalInstance, ProjectService, MessageService, projects, project,SweetAlert,ProjectModel,$cookieStore,$route) {
     $scope.state = {
         isEdit: false,
         oldProjName: null
@@ -213,6 +212,11 @@ var projCtrl = function ($scope, $modalInstance, ProjectService, MessageService,
             };
             ProjectService.update({}, requestBody, function (newProj) {
                 SweetAlert.swal('Success!', 'Project update successfully!', 'success');
+
+                //update project in project model
+                ProjectModel.updateProject($scope.proj.name,$scope.state.oldProjName);
+                $cookieStore.put("project",$scope.proj.name);
+                ProjectModel.setSelectedProject($scope.proj.name);
                 $modalInstance.dismiss('cancel');
             },function(e){
                 if(e.data&& e.data.exception){
@@ -232,6 +236,10 @@ var projCtrl = function ($scope, $modalInstance, ProjectService, MessageService,
                 if(projects) {
                     projects.push(newProj);
                 }
+                ProjectModel.addProject(newProj.name);
+                $cookieStore.put("project",newProj.name);
+                location.reload();
+
             }, function(e){
                 if(e.data&& e.data.exception){
                     var message =e.data.exception;
@@ -248,5 +256,4 @@ var projCtrl = function ($scope, $modalInstance, ProjectService, MessageService,
         $modalInstance.dismiss('cancel');
     };
 
-
 };

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/projectMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/projectMeta.js b/webapp/app/js/controllers/projectMeta.js
index bcc6922..0a5c04a 100644
--- a/webapp/app/js/controllers/projectMeta.js
+++ b/webapp/app/js/controllers/projectMeta.js
@@ -31,7 +31,7 @@ KylinApp
             var defer = $q.defer();
             $scope.selectedSrcDb = [];
             $scope.loading = true;
-            QueryService.getTables({project: $scope.project.selectedProject}, {}, function (tables) {
+            QueryService.getTables({project: $scope.projectModel.selectedProject}, {}, function (tables) {
                 var tableMap = [];
                 angular.forEach(tables, function (table) {
                     if (!tableMap[table.table_SCHEM]) {
@@ -59,7 +59,7 @@ KylinApp
         };
 
 
-        $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+        $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
             if(newValue){
                 $scope.projectMetaLoad();
             }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/query.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/query.js b/webapp/app/js/controllers/query.js
index 397b6db..a1ec269 100644
--- a/webapp/app/js/controllers/query.js
+++ b/webapp/app/js/controllers/query.js
@@ -45,7 +45,7 @@ KylinApp
                 var query = {
                     originSql: sql,
                     sql: sql,
-                    project: (!!project)? project:$scope.project.selectedProject,
+                    project: (!!project)? project:$scope.projectModel.selectedProject,
                     status: 'executing',
                     acceptPartial: true,
                     result: {

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/controllers/sourceMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js
index bb8b8af..5edb33b 100644
--- a/webapp/app/js/controllers/sourceMeta.js
+++ b/webapp/app/js/controllers/sourceMeta.js
@@ -52,7 +52,7 @@ KylinApp
             $scope.loading = true;
             var param = {
                 ext: true,
-                project:$scope.project.selectedProject
+                project:$scope.projectModel.selectedProject
             };
             if (forceLoad)
             {
@@ -96,7 +96,7 @@ KylinApp
             return defer.promise;
         };
 
-        $scope.$watch('project.selectedProject', function (newValue, oldValue) {
+        $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
 //         will load table when enter this page,null or not
         $scope.aceSrcTbLoaded();
 
@@ -136,7 +136,7 @@ KylinApp
                       return $scope.tableNames;
                     },
                     projectName:function(){
-                      return  $scope.project.selectedProject;
+                      return  $scope.projectModel.selectedProject;
                     },
                     hiveTbLoad:function(){
                       return $scope.hiveTbLoad;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/filters/filter.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/filters/filter.js b/webapp/app/js/filters/filter.js
index b405e77..7fa111e 100644
--- a/webapp/app/js/filters/filter.js
+++ b/webapp/app/js/filters/filter.js
@@ -88,11 +88,15 @@ KylinApp
 
         var gmttimezone;
         //convert GMT+0 time to specified Timezone
-        return function(item,timezone){
+        return function(item,timezone,format){
 
             if(!timezone){
                 timezone = kylinConfig.getTimeZone();
             }
+            if(!format){
+                format ="yyyy-MM-dd HH:mm:ss";
+            }
+
             //convert short name timezone to GMT
             switch(timezone){
                 //convert PST to GMT

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/model/cubeConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/cubeConfig.js b/webapp/app/js/model/cubeConfig.js
new file mode 100644
index 0000000..718dfe0
--- /dev/null
+++ b/webapp/app/js/model/cubeConfig.js
@@ -0,0 +1,51 @@
+/**
+ * Created by jiazhong on 2014/12/30.
+ *
+ * Define consstant value for CubeDesc
+ *
+ */
+KylinApp.constant('cubeConfig', {
+
+    //~ Define metadata & class
+    measureParamType : ['column', 'constant'],
+    measureExpressions : ['SUM', 'MIN', 'MAX', 'COUNT', 'COUNT_DISTINCT'],
+    dimensionDataTypes : ["string", "tinyint", "int", "bigint", "date"],
+    cubeCapacities : ["SMALL", "MEDIUM","LARGE"],
+//    cubePartitionTypes : ['APPEND', 'UPDATE_INSERT'],
+    cubePartitionTypes : ['APPEND'],
+    joinTypes : [
+        {name: 'Left', value: 'left'},
+        {name: 'Inner', value: 'inner'},
+        {name: 'Right', value: 'right'}
+    ],
+    queryPriorities : [
+        {name: 'NORMAL', value: 50},
+        {name: 'LOW', value: 70},
+        {name: 'HIGH', value: 30}
+    ],
+    measureDataTypes : [
+        {name: 'INT', value: 'int'},
+        {name: 'BIGINT', value: 'bigint'},
+        {name: 'DECIMAL', value: 'decimal'},
+        {name: 'DOUBLE', value: 'double'},
+        {name: 'DATE', value: 'date'},
+        {name: 'STRING', value: 'string'}
+    ],
+    distinctDataTypes : [
+        {name: 'Error Rate < 9.75%', value: 'hllc10'},
+        {name: 'Error Rate < 4.88%', value: 'hllc12'},
+        {name: 'Error Rate < 2.44%', value: 'hllc14'},
+        {name: 'Error Rate < 1.72%', value: 'hllc15'},
+        {name: 'Error Rate < 1.22%', value: 'hllc16'}
+    ],
+    dftSelections : {
+        measureExpression: 'SUM',
+        measureParamType: 'column',
+        measureDataType: {name: 'BIGINT', value: 'bigint'},
+        distinctDataType: {name: 'Error Rate < 2.44%', value: 'hllc14'},
+        cubeCapacity: 'MEDIUM',
+        queryPriority: {name: 'NORMAL', value: 50},
+        cubePartitionType: 'APPEND'
+    },
+    dictionaries : ["true", "false"]
+    });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/model/cubeDescModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/cubeDescModel.js b/webapp/app/js/model/cubeDescModel.js
new file mode 100644
index 0000000..6b4def7
--- /dev/null
+++ b/webapp/app/js/model/cubeDescModel.js
@@ -0,0 +1,45 @@
+KylinApp.service('CubeDescModel',function(){
+
+    this.cubeMetaFrame = {};
+
+    //
+    this.createNew = function () {
+            var cubeMeta = {
+                "name": "",
+                "description": "",
+                "fact_table": "",
+                "filter_condition": null,
+                "notify_list": [],
+                "cube_partition_desc": {
+                    "partition_date_column": null,
+                    "partition_date_start": null,
+                    "cube_partition_type": null
+                },
+                "capacity": "",
+                "cost": 50,
+                "dimensions": [],
+                "measures": [
+                    {   "id": 1,
+                        "name": "_COUNT_",
+                        "function": {
+                            "expression": "COUNT",
+                            "returntype": "bigint",
+                            "parameter": {
+                                "type": "constant",
+                                "value": "1"
+                            }
+                        }
+                    }
+                ],
+                "rowkey": {
+                    "rowkey_columns": [],
+                    "aggregation_groups": []
+                },
+                "hbase_mapping": {
+                    "column_family": []
+                }
+            };
+
+            return cubeMeta;
+        }
+})
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/js/model/projectModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/projectModel.js b/webapp/app/js/model/projectModel.js
new file mode 100644
index 0000000..d08f805
--- /dev/null
+++ b/webapp/app/js/model/projectModel.js
@@ -0,0 +1,46 @@
+KylinApp.service('ProjectModel',function(){
+
+    this.projects = [];
+    this.selectedProject =null;
+
+
+    this.setSelectedProject = function(project) {
+        if(this.projects.indexOf(project) > -1) {
+            this.selectedProject = project;
+        }
+    };
+
+    this.setProjects = function(projects){
+        if(projects.length){
+            this.projects = projects;
+        }
+    }
+
+    this.addProject = function(project){
+        this.projects.push(project);
+        this.sortProjects();
+    }
+
+    this.removeProject = function(project){
+        var index =this.projects.indexOf(project);
+        if(index>-1){
+            this.projects.splice(index,1);
+        }
+    }
+
+    this.updateProject = function (_new,_old) {
+        var index =this.projects.indexOf(_old);
+        if(index>-1){
+            this.projects[index] = _new;
+        }
+    }
+
+    this.getProjects = function(){
+        return this.projects;
+    }
+
+    this.sortProjects = function (){
+        this.projects = _.sortBy(this.projects, function (i) { return i.toLowerCase(); });
+    }
+
+})
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubeDesigner/advanced_settings.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/advanced_settings.html b/webapp/app/partials/cubeDesigner/advanced_settings.html
index 7db3077..04812b4 100644
--- a/webapp/app/partials/cubeDesigner/advanced_settings.html
+++ b/webapp/app/partials/cubeDesigner/advanced_settings.html
@@ -13,7 +13,7 @@
                             <div class="col-xs-12 col-sm-6">
                                 <select class="form-control" ng-if="state.mode=='edit'" style="width: 360px;"
                                         chosen ng-model="cubeMetaFrame.capacity" required
-                                        ng-options="cc as cc for cc in cubeCapacities">
+                                        ng-options="cc as cc for cc in cubeConfig.cubeCapacities">
                                 </select>
                                 <span ng-if="state.mode=='view'">{{cubeMetaFrame.capacity}}</span>
                             </div>
@@ -106,7 +106,7 @@
                     <div>
                         <select ng-if="state.mode=='edit'" style="width:80px;"
                                 chosen ng-model="rowkey_column.dictionary"
-                                ng-options="dt as dt for dt in dictionaries">
+                                ng-options="dt as dt for dt in cubeConfig.dictionaries">
                         </select>
                         <span ng-if="state.mode=='view'">{{rowkey_column.dictionary}}</span>
                     </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubeDesigner/data_model.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/data_model.html b/webapp/app/partials/cubeDesigner/data_model.html
index d717d74..d20478c 100644
--- a/webapp/app/partials/cubeDesigner/data_model.html
+++ b/webapp/app/partials/cubeDesigner/data_model.html
@@ -107,7 +107,7 @@
                         <label class="col-sm-3 control-label font-color-default"><b>Join Type</b></label>
                         <div class="col-sm-6">
                             <select class="form-control" chosen ng-model="newLookup.join.type"
-                                    ng-options="joinType.value as joinType.name for joinType in joinTypes">
+                                    ng-options="joinType.value as joinType.name for joinType in cubeConfig.joinTypes">
                             </select>
                         </div>
                     </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubeDesigner/incremental.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/incremental.html b/webapp/app/partials/cubeDesigner/incremental.html
index 2b3dc71..97825c2 100644
--- a/webapp/app/partials/cubeDesigner/incremental.html
+++ b/webapp/app/partials/cubeDesigner/incremental.html
@@ -9,7 +9,7 @@
                     <select class="form-control"
                         ng-if="state.mode=='edit'"
                         chosen ng-model="cubeMetaFrame.cube_partition_desc.cube_partition_type" required
-                        ng-options="ddt as ddt for ddt in cubePartitionTypes">
+                        ng-options="ddt as ddt for ddt in cubeConfig.cubePartitionTypes">
                     </select>
                     <span ng-if="state.mode=='view'">{{cubeMetaFrame.cube_partition_desc.cube_partition_type}}</span>
                 </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubeDesigner/measures.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/measures.html b/webapp/app/partials/cubeDesigner/measures.html
index 1f00189..6e68e2b 100644
--- a/webapp/app/partials/cubeDesigner/measures.html
+++ b/webapp/app/partials/cubeDesigner/measures.html
@@ -92,9 +92,8 @@
                             <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"><b>Expression</b></label>
                             <div class="col-xs-12 col-sm-6">
                                 <select class="form-control"
-                                    ng-init="newMeasure.function.expression = (!!newMeasure.function.expression)?newMeasure.function.expression:dftSelections.measureExpression"
-                                    chosen ng-model="newMeasure.function.expression" required
-                                    ng-options="me as me for me in measureExpressions">
+                                    ng-init="newMeasure.function.expression = (!!newMeasure.function.expression)?newMeasure.function.expression:cubeConfig.dftSelections.measureExpression"                                    chosen ng-model="newMeasure.function.expression" required
+                                    ng-options="me as me for me in cubeConfig.measureExpressions">
                                 </select>
                             </div>
                         </div>
@@ -107,7 +106,7 @@
                                 <select class="form-control" ng-if="newMeasure.function.expression != 'COUNT'"
                                     ng-init="newMeasure.function.parameter.type=(!!newMeasure.function.parameter.type)?newMeasure.function.parameter.type: 'column' "
                                     chosen ng-model="newMeasure.function.parameter.type" required
-                                    ng-options="mpt as mpt for mpt in measureParamType">
+                                    ng-options="mpt as mpt for mpt in cubeConfig.measureParamType">
                                 </select>
                                 <span class="font-color-default"
                                        ng-if="newMeasure.function.expression == 'COUNT'"
@@ -140,16 +139,16 @@
                             <div class="col-xs-12 col-sm-6">
                                 <select class="form-control"
                                     ng-if="newMeasure.function.expression != 'COUNT_DISTINCT' && newMeasure.function.expression != 'COUNT' "
-                                    ng-init="newMeasure.function.returntype = (!!newMeasure.function.returntype)?newMeasure.function.returntype:dftSelections.measureDataType.value"
+                                    ng-init="newMeasure.function.returntype = (!!newMeasure.function.returntype)?newMeasure.function.returntype:cubeConfig.dftSelections.measureDataType.value"
                                     chosen ng-model="newMeasure.function.returntype" required
-                                    ng-options="mdt.value as mdt.name for mdt in measureDataTypes">
+                                    ng-options="mdt.value as mdt.name for mdt in cubeConfig.measureDataTypes">
                                     <option value=""></option>
                                 </select>
                                 <select class="form-control"
                                     ng-if="newMeasure.function.expression == 'COUNT_DISTINCT'"
-                                    ng-init="newMeasure.function.returntype = (!!newMeasure.function.returntype)?newMeasure.function.returntype:dftSelections.distinctDataType.value"
+                                    ng-init="newMeasure.function.returntype = (!!newMeasure.function.returntype)?newMeasure.function.returntype:cubeConfig.dftSelections.distinctDataType.value"
                                     chosen ng-model="newMeasure.function.returntype" required
-                                    ng-options="ddt.value as ddt.name for ddt in distinctDataTypes">
+                                    ng-options="ddt.value as ddt.name for ddt in cubeConfig.distinctDataTypes">
                                     <option value=""></option>
                                 </select>
                                 <span class="font-color-default"

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubes/cube_json_edit.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubes/cube_json_edit.html b/webapp/app/partials/cubes/cube_json_edit.html
index 206cb02..eec0b05 100644
--- a/webapp/app/partials/cubes/cube_json_edit.html
+++ b/webapp/app/partials/cubes/cube_json_edit.html
@@ -10,7 +10,7 @@
                         <form class="navbar-form navbar-left" style="margin-top: 0px !important;" ng-if="userService.isAuthorized()">
                             <div class="form-group">
                                 <span><b>Project: </b></span>
-                                <select chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                                <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
                                         ng-options="project as project for project in project.projects"
                                         style="width: 150px"
                                         class="chosen-select">
@@ -32,7 +32,7 @@
                                     }" ng-model="state.cubeSchema">
                     </div>
                 </section>
-                <button class="btn btn-primary" ng-disabled="cube_form.$invalid" ng-click="state.project = project.selectedProject;saveCube()">
+                <button class="btn btn-primary" ng-disabled="cube_form.$invalid" ng-click="state.project = projectModel.selectedProject;saveCube()">
                     Save
                 </button>
             </form>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/cubes/cubes.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubes/cubes.html b/webapp/app/partials/cubes/cubes.html
index eea71c1..e67e624 100644
--- a/webapp/app/partials/cubes/cubes.html
+++ b/webapp/app/partials/cubes/cubes.html
@@ -4,12 +4,12 @@
         <form ng-if="userService.isAuthorized()">
             <div class="form-group">
                 <span><b>Project: </b></span>
-                <select chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                        ng-options="project as project for project in project.projects"
+                <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                        ng-options="project as project for project in projectModel.projects"
                         style="width: 150px"
                         data-placeholder="select a project"
                         class="chosen-select">
-                    <option ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="project.selectedProject==null" value=""> -- Select All -- </option>
+                    <option ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="projectModel.selectedProject==null" value=""> -- Select All -- </option>
                 </select>
                 <!--Project-->
                 <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/jobs/job_steps.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/jobs/job_steps.html b/webapp/app/partials/jobs/job_steps.html
index 91019a0..d7da22c 100644
--- a/webapp/app/partials/jobs/job_steps.html
+++ b/webapp/app/partials/jobs/job_steps.html
@@ -51,7 +51,7 @@
         <!--Start Label-->
         <li class="time-label">
             <span class="bg-blue">
-                <b>Start &nbsp;&nbsp;{{state.selectedJob.steps[0].exec_start_time !=0 ? (state.selectedJob.steps[0].exec_start_time | utcToConfigTimeZone) :''}}</b>
+                <b>Start &nbsp;&nbsp;{{state.selectedJob.steps[0].exec_start_time !=0 ? (state.selectedJob.steps[0].exec_start_time | utcToConfigTimeZone::'HH:mm:ss yyyy-MM-dd') :''}}</b>
             </span>
         </li>
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/jobs/jobs.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/jobs/jobs.html b/webapp/app/partials/jobs/jobs.html
index 16e32a0..aea11ea 100644
--- a/webapp/app/partials/jobs/jobs.html
+++ b/webapp/app/partials/jobs/jobs.html
@@ -4,12 +4,12 @@
         <form ng-if="userService.isAuthorized()">
             <div class="form-group">
                 <span><b>Project: </b></span>
-                <select chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                        ng-options="project as project for project in project.projects"
+                <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                        ng-options="project as project for project in projectModel.projects"
                         style="width: 150px"
                         data-placeholder="select a project"
                         class="chosen-select">
-                    <option ng-if="userService.hasRole('ROLE_ADMIN')"  ng-selected="project.selectedProject==null"  value=""> -- Select All -- </option>
+                    <option ng-if="userService.hasRole('ROLE_ADMIN')"  ng-selected="projectModel.selectedProject==null"  value=""> -- Select All -- </option>
                 </select>
                 <!--Project-->
                 <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/login.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/login.html b/webapp/app/partials/login.html
index 3c423d2..b450040 100644
--- a/webapp/app/partials/login.html
+++ b/webapp/app/partials/login.html
@@ -27,8 +27,8 @@
                                 <div class="form-group">
                                     <span>
 
-                                        <select  ng-required="project.projects.length" chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                                                ng-options="project as project for project in project.projects "
+                                        <select  ng-required="projectModel.projects.length" chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                                                ng-options="project as project for project in projectModel.projects "
                                                 style="width: 100% !important;"
                                                 data-placeholder="select a project"
                                                 class="chosen-select">

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/query/query.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/query/query.html b/webapp/app/partials/query/query.html
index a9c51bf..1f3a60a 100644
--- a/webapp/app/partials/query/query.html
+++ b/webapp/app/partials/query/query.html
@@ -3,12 +3,12 @@
     <form class="navbar-form navbar-left" style="margin-top: 0px !important;" ng-if="userService.isAuthorized()">
         <div class="form-group">
             <span><b>Project: </b></span>
-            <select chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                    ng-options="project as project for project in project.projects"
+            <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                    ng-options="project as project for project in projectModel.projects"
                     style="width: 150px"
                     data-placeholder="select a project"
                     class="chosen-select">
-                <option ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="project.selectedProject==null"  value=""> -- Choose Project -- </option>
+                <option ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="projectModel.selectedProject==null"  value=""> -- Choose Project -- </option>
             </select>
             <!--Project-->
             <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a>
@@ -54,7 +54,7 @@
                     </p>
                     <div class="pull-left">
                         <h4>
-                            Project: <span class="label label-info">{{project.selectedProject}}</span>
+                            Project: <span class="label label-info">{{projectModel.selectedProject}}</span>
                         </h4>
                     </div>
                     <div class="pull-right">

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/17817ed1/webapp/app/partials/tables/source_metadata.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/source_metadata.html b/webapp/app/partials/tables/source_metadata.html
index c0a2179..cef0433 100644
--- a/webapp/app/partials/tables/source_metadata.html
+++ b/webapp/app/partials/tables/source_metadata.html
@@ -3,12 +3,12 @@
     <form class="navbar-form navbar-left" style="margin-top: 0px !important;" ng-if="userService.isAuthorized()">
         <div class="form-group">
             <span><b>Project: </b></span>
-            <select chosen ng-model="project.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                    ng-options="project as project for project in project.projects"
+            <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
+                    ng-options="project as project for project in projectModel.projects"
                     style="width: 150px"
                     data-placeholder="select a project"
                     class="chosen-select">
-                <option  ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="project.selectedProject==null"  value=""> -- Choose Project -- </option>
+                <option  ng-if="userService.hasRole('ROLE_ADMIN')" ng-selected="projectModel.selectedProject==null"  value=""> -- Choose Project -- </option>
             </select>
             <!--Project-->
             <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a>