You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ma...@apache.org on 2015/05/15 07:21:55 UTC

[26/52] [abbrv] incubator-kylin git commit: switch tab models, data source in models page

switch tab models,data source in models page


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

Branch: refs/heads/0.8.0
Commit: 16b6664144cac64f8c0606e472b71e4cd6a97d17
Parents: c3394d6
Author: jiazhong <ji...@ebay.com>
Authored: Thu Mar 19 19:56:55 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:36:51 2015 +0800

----------------------------------------------------------------------
 .../kylin/metadata/model/DataModelDesc.java     |  34 +++++
 .../kylin/metadata/project/ProjectInstance.java |   3 -
 .../kylin/rest/controller/CubeController.java   |   4 +-
 .../kylin/rest/controller/ModelController.java  |  35 +++--
 webapp/app/js/controllers/modelEdit.js          |  43 ++----
 webapp/app/js/controllers/modelSchema.js        |  29 ----
 webapp/app/js/controllers/models.js             |  42 +++---
 webapp/app/js/controllers/page.js               |  13 +-
 webapp/app/js/model/modelList.js                |   5 +-
 webapp/app/js/model/projectModel.js             |  27 +++-
 webapp/app/js/services/tree.js                  |  33 -----
 webapp/app/less/component.less                  |   3 +
 webapp/app/partials/header.html                 |   2 +-
 webapp/app/partials/login.html                  |   2 +-
 .../modelDesigner/conditions_settings.html      |   2 +-
 .../modelDesigner/model_dimensions.html         |   2 +-
 .../app/partials/modelDesigner/model_info.html  |   3 +-
 .../partials/modelDesigner/model_measures.html  |   2 +-
 webapp/app/partials/models/model_detail.html    |  25 +---
 webapp/app/partials/models/model_schema.html    |   9 +-
 webapp/app/partials/models/models.html          |  16 ++-
 .../app/partials/tables/source_table_tree.html  |   2 +-
 webapp/app/partials/tables/table_detail.html    | 138 +++++++++++++++++++
 23 files changed, 302 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java b/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
index cd0caee..7e888c2 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
@@ -61,6 +61,13 @@ public class DataModelDesc extends RootPersistentEntity {
     @JsonProperty("capacity")
     private RealizationCapacity capacity = RealizationCapacity.MEDIUM;
 
+
+    /**
+     * Error messages during resolving json metadata
+     */
+    private List<String> errors = new ArrayList<String>();
+
+
     public String getName() {
         return name;
     }
@@ -214,6 +221,33 @@ public class DataModelDesc extends RootPersistentEntity {
         }
     }
 
+    /**
+     * Add error info and thrown exception out
+     *
+     * @param message
+     */
+    public void addError(String message) {
+        addError(message, false);
+    }
+
+    /**
+     * @param message
+     *            error message
+     * @param silent
+     *            if throw exception
+     */
+    public void addError(String message, boolean silent) {
+        if (!silent) {
+            throw new IllegalStateException(message);
+        } else {
+            this.errors.add(message);
+        }
+    }
+
+    public List<String> getError() {
+        return this.errors;
+    }
+
     @Override
     public String toString() {
         return "DataModelDesc [name=" + name + "]";

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectInstance.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectInstance.java b/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectInstance.java
index 387f735..7575ff7 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectInstance.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectInstance.java
@@ -242,14 +242,12 @@ public class ProjectInstance extends RootPersistentEntity {
     }
 
     public boolean containsModel(String modelName) {
-        modelName = modelName.toUpperCase();
         return models!=null&&models.contains(modelName);
     }
 
     public void setModels(List<String> models) { this.models = models; }
 
     public void addModel(String modelName) {
-        modelName = modelName.toUpperCase();
         if(this.getModels()==null){
             this.setModels(new ArrayList<String>());
         }
@@ -257,7 +255,6 @@ public class ProjectInstance extends RootPersistentEntity {
     }
 
     public void removeModel(String modelName){
-        modelName = modelName.toUpperCase();
         if(this.getModels()!=null) {
             this.getModels().remove(modelName);
         }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java b/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
index bc8f09a..fb1870b 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
@@ -358,12 +358,12 @@ public class CubeController extends BasicController {
         if (desc.getError().isEmpty()) {
             cubeRequest.setSuccessful(true);
         } else {
-            logger.warn("Cube " + desc.getName() + " fail to create because " + desc.getError());
+            logger.warn("Cube " + desc.getName() + " fail to update because " + desc.getError());
             updateRequest(cubeRequest, false, omitMessage(desc.getError()));
         }
         String descData = JsonUtil.writeValueAsIndentString(desc);
         cubeRequest.setCubeDescData(descData);
-
+        cubeRequest.setSuccessful(true);
         return cubeRequest;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java b/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
index 97a5d32..5a18a3b 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
@@ -17,7 +17,7 @@
 */
 
 package org.apache.kylin.rest.controller;
-
+import java.util.Iterator;
 import com.codahale.metrics.annotation.Metered;
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -27,12 +27,14 @@ import org.apache.kylin.common.util.JsonUtil;
 import org.apache.kylin.metadata.model.DataModelDesc;
 import org.apache.kylin.metadata.project.ProjectInstance;
 import org.apache.kylin.rest.exception.BadRequestException;
+import org.apache.kylin.rest.exception.ForbiddenException;
 import org.apache.kylin.rest.exception.InternalErrorException;
 import org.apache.kylin.rest.request.ModelRequest;
 import org.apache.kylin.rest.service.ModelService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDeniedException;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.*;
 
@@ -106,24 +108,27 @@ public class ModelController extends BasicController {
     @ResponseBody
     @Metered(name = "updateModel")
     public ModelRequest updateModelDesc(@RequestBody ModelRequest modelRequest) throws JsonProcessingException {
-
-        //Update Model
         DataModelDesc modelDesc = deserializeDataModelDesc(modelRequest);
         if (modelDesc == null) {
             return modelRequest;
         }
-
         try {
-            modelService.updateModelAndDesc(modelDesc,modelRequest.getProject());
-        } catch (IOException e) {
-            // TODO Auto-generated catch block
+            modelDesc =  modelService.updateModelAndDesc(modelDesc,modelRequest.getProject());
+        } catch (AccessDeniedException accessDeniedException) {
+            throw new ForbiddenException("You don't have right to update this cube.");
+        }  catch (Exception e) {
             logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
             throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
         }
 
+        if (modelDesc.getError().isEmpty()) {
+            modelRequest.setSuccessful(true);
+        } else {
+            logger.warn("Model " + modelDesc.getName() + " fail to update because " + modelDesc.getError());
+            updateRequest(modelRequest, false, omitMessage(modelDesc.getError()));
+        }
         String descData = JsonUtil.writeValueAsIndentString(modelDesc);
         modelRequest.setModelDescData(descData);
-
         return modelRequest;
     }
 
@@ -156,5 +161,17 @@ public class ModelController extends BasicController {
         this.modelService = modelService;
     }
 
-
+    /**
+     * @param errors
+     * @return
+     */
+    private String omitMessage(List<String> errors) {
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator<String> iterator = errors.iterator(); iterator.hasNext();) {
+            String string = (String) iterator.next();
+            buffer.append(string);
+            buffer.append("\n");
+        }
+        return buffer.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/controllers/modelEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelEdit.js b/webapp/app/js/controllers/modelEdit.js
index 38290f7..364919d 100644
--- a/webapp/app/js/controllers/modelEdit.js
+++ b/webapp/app/js/controllers/modelEdit.js
@@ -64,10 +64,20 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
 
     // ~ init
     if ($scope.isEdit = !!$routeParams.modelName) {
+
+
+
         var modelName = $routeParams.modelName;
         ModelDescService.get({model_name: modelName}, function (model) {
                     if (model) {
                         $scope.model = model;
+                        $scope.model.project = ProjectModel.getProjectByCubeModel(modelName);
+
+                        if(!ProjectModel.getSelectedProject()){
+                            ProjectModel.setSelectedProject($scope.model.project);
+                            TableModel.aceSrcTbLoaded();
+                        }
+
                         //use
                         //convert GMT mills ,to make sure partition date show GMT Date
                         //should run only one time
@@ -78,39 +88,11 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
                     }
                 });
         //init project
-            ProjectService.list({}, function (projects) {
-                $scope.projects = projects;
-                if (modelName) {
-                    var projName = null;
-                    if(ProjectModel.getSelectedProject()){
-                        projName=ProjectModel.getSelectedProject();
-                    }else{
-                        angular.forEach($scope.projects, function (project, index) {
-                            angular.forEach(project.models, function (unit, index) {
-                                if (!projName && unit === modelName) {
-                                    projName = project.name;
-                                }
-                            });
-                        });
-                    }
-
-                    if(!ProjectModel.getSelectedProject()){
-                        ProjectModel.setSelectedProject(projName);
-                        TableModel.aceSrcTbLoaded();
-                    }
-
-                    $scope.state.project = projName;
-                }
-
-                angular.forEach($scope.projects, function (project, index) {
-                    $scope.listAccess(project, 'ProjectInstance');
-                });
-            });
-
 
     } else {
         MetaModel.initModel();
         $scope.model = MetaModel.getMetaModel();
+        $scope.model.project = ProjectModel.getSelectedProject();
     }
 
     $scope.prepareModel = function () {
@@ -128,8 +110,9 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
             }
 
         }
+        $scope.state.project = $scope.model.project;
+        delete $scope.model.project;
         $scope.state.modelSchema = angular.toJson($scope.model, true);
-//        $scope.state.project = $scope.projectModel.selectedProject;
 
     };
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index 198a9a3..b2b7ba7 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -112,35 +112,6 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
 
     // ~ private methods
     function initProject() {
-        ProjectService.list({}, function (projects) {
-            $scope.projects = projects;
-
-            var cubeName = (!!$scope.routeParams.cubeName)? $scope.routeParams.cubeName:$scope.state.cubeName;
-            if (cubeName) {
-                var projName = null;
-                if(ProjectModel.getSelectedProject()){
-                    projName=ProjectModel.getSelectedProject();
-                }else{
-                    angular.forEach($scope.projects, function (project, index) {
-                        angular.forEach(project.realizations, function (unit, index) {
-                            if (!projName && unit.type=="CUBE"&&unit.realization === cubeName) {
-                                projName = project.name;
-                            }
-                        });
-                    });
-                }
-
-                if(!ProjectModel.getSelectedProject()){
-                    ProjectModel.setSelectedProject(projName);
-                    TableModel.aceSrcTbLoaded();
-                }
-
-                $scope.cubeMetaFrame.project = projName;
-            }
 
-            angular.forEach($scope.projects, function (project, index) {
-                $scope.listAccess(project, 'ProjectInstance');
-            });
-        });
     }
 });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/controllers/models.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/models.js b/webapp/app/js/controllers/models.js
index fb6c964..9f93ab6 100644
--- a/webapp/app/js/controllers/models.js
+++ b/webapp/app/js/controllers/models.js
@@ -18,8 +18,19 @@
 
 'use strict';
 
-KylinApp
-    .controller('ModelsCtrl', function ($scope, $q, $routeParams, $location, $window,$modal, MessageService, CubeDescService, CubeService, JobService, UserService,  ProjectService,SweetAlert,loadingRequest,$log,modelConfig,ProjectModel,ModelService,MetaModel,ModelList) {
+KylinApp.controller('ModelsCtrl', function ($scope, $q, $routeParams, $location, $window,$modal, MessageService, CubeDescService, CubeService, JobService, UserService,  ProjectService,SweetAlert,loadingRequest,$log,modelConfig,ProjectModel,ModelService,MetaModel,ModelList) {
+        //selected model
+        $scope.model = {};
+        //tree data
+        $scope.models_treedata=[];
+
+        $scope.showModels=true;
+
+        $scope.toggleTab = function(showModel){
+            $scope.showModels = showModel;
+//            console.log($scope.showModels);
+        }
+
         $scope.modelList = ModelList;
         $scope.modelConfig = modelConfig;
         ModelList.removeAll();
@@ -32,10 +43,6 @@ KylinApp
         };
 
 
-        //tree data
-        $scope.models_treedata=[];
-
-
         //  TODO offset&limit
         $scope.list = function (offset, limit) {
             if(!$scope.projectModel.projects.length){
@@ -68,31 +75,34 @@ KylinApp
             $scope.list().then(function(resp){
                 $scope.models_treedata = [];
                 angular.forEach(ModelList.models,function(model){
-                    var _model = {label:model.name,noLeaf:true}
-                    var _children = []
+                    var _model = {
+                        label:model.name,
+                        noLeaf:true,
+                        data:model,
+                        onSelect:function(branch){
+                         // set selecte model
+                            $scope.model=branch.data;
+                        }
+                    };
+                    var _children = [];
                     angular.forEach(model.cubes,function(cube){
                         _children.push(cube.name);
                     });
                     if(_children.length){
                          _model.children = _children;
                     }
-//                    _model.children=[''];
                     $scope.models_treedata.push(_model);
                 });
+                $scope.models_treedata = _.sortBy($scope.models_treedata, function (i) { return i.label.toLowerCase(); });
 
             });
         };
 
         $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
-            if(newValue||newValue==null){
                 ModelList.removeAll();
+                //init selected model
+                $scope.model = {};
                 $scope.init();
-            }
-
         });
-        $scope.reload = function () {
-            // trigger reload action in pagination directive
-            $scope.action.reload = !$scope.action.reload;
-        };
 
     });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/controllers/page.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/page.js b/webapp/app/js/controllers/page.js
index 6cc2762..73bcf0f 100644
--- a/webapp/app/js/controllers/page.js
+++ b/webapp/app/js/controllers/page.js
@@ -46,9 +46,10 @@ KylinApp.controller('PageCtrl', function ($scope, $q, AccessService,$modal, $loc
     ProjectService.list({}, function (projects) {
         var _projects = [];
         angular.forEach(projects, function(project, index){
-            _projects.push(project.name);
+            $scope.listAccess(project, 'ProjectInstance');
+            _projects.push(project);
         });
-        _projects = _.sortBy(_projects, function (i) { return i.toLowerCase(); });
+        _projects = _.sortBy(_projects, function (i) { return i.name.toLowerCase(); });
 
         ProjectModel.setProjects(_projects);
 
@@ -251,10 +252,10 @@ var projCtrl = function ($scope,$location, $modalInstance, ProjectService, Messa
             ProjectService.save({}, $scope.proj, function (newProj) {
                 SweetAlert.swal('Success!', 'New project created successfully!', 'success');
                 $modalInstance.dismiss('cancel');
-                if(projects) {
-                    projects.push(newProj);
-                }
-                ProjectModel.addProject(newProj.name);
+//                if(projects) {
+//                    projects.push(newProj);
+//                }
+//                ProjectModel.addProject(newProj);
                 $cookieStore.put("project",newProj.name);
                 location.reload();
             }, function(e){

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/model/modelList.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/modelList.js b/webapp/app/js/model/modelList.js
index 1161f47..6d56a10 100644
--- a/webapp/app/js/model/modelList.js
+++ b/webapp/app/js/model/modelList.js
@@ -16,7 +16,7 @@
  * limitations under the License.
 */
 
-KylinApp.service('ModelList',function(ModelService,CubeService,$q,AccessService){
+KylinApp.service('ModelList',function(ModelService,CubeService,$q,AccessService,ProjectModel){
     var models=[];
     var _this = this;
 
@@ -32,6 +32,8 @@ KylinApp.service('ModelList',function(ModelService,CubeService,$q,AccessService)
                 CubeService.list({offset: 0, limit: 70,modelName:model.name}, function (_cubes) {
                     model.cubes=_cubes;
                 });
+
+                model.project =ProjectModel.getProjectByCubeModel(model.name);
             });
             _models = _.filter(_models,function(models){return models.name!=undefined});
             _this.models = _this.models.concat(_models);
@@ -54,4 +56,5 @@ KylinApp.service('ModelList',function(ModelService,CubeService,$q,AccessService)
     this.removeAll = function(){
         _this.models=[];
     };
+
 });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/model/projectModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/projectModel.js b/webapp/app/js/model/projectModel.js
index b0c05fe..934424f 100644
--- a/webapp/app/js/model/projectModel.js
+++ b/webapp/app/js/model/projectModel.js
@@ -23,9 +23,7 @@ KylinApp.service('ProjectModel',function(){
 
 
     this.setSelectedProject = function(project) {
-        if(this.projects.indexOf(project) > -1) {
             this.selectedProject = project;
-        }
     };
     this.getSelectedProject = function(project) {
          return this.selectedProject;
@@ -52,9 +50,11 @@ KylinApp.service('ProjectModel',function(){
     }
 
     this.updateProject = function (_new,_old) {
-        var index =this.projects.indexOf(_old);
-        if(index>-1){
-            this.projects[index] = _new;
+        for(var i = 0;i<projects.length; i++){
+          if(projects[i].name === _old){
+              projects[i].name = _new;
+              break;
+          }
         }
     }
 
@@ -62,8 +62,23 @@ KylinApp.service('ProjectModel',function(){
         return this.projects;
     }
 
+    this.getProjectByCubeModel = function(modelName){
+        for(var i = 0;i<this.projects.length;i++){
+            if(!this.projects[i].models){
+                continue;
+            }
+            for(var j = 0;j<this.projects[i].models.length;j++){
+                var model = this.projects[i].models[j];
+                if(model.toUpperCase()===modelName.toUpperCase()){
+                    return this.projects[i].name;
+                }
+            }
+        };
+        return this.getSelectedProject();
+    }
+
     this.sortProjects = function (){
-        this.projects = _.sortBy(this.projects, function (i) { return i.toLowerCase(); });
+        this.projects = _.sortBy(this.projects, function (i) { return i.name.toLowerCase(); });
     }
 
 })

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/js/services/tree.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/tree.js b/webapp/app/js/services/tree.js
index 4b1ef2d..d61629c 100755
--- a/webapp/app/js/services/tree.js
+++ b/webapp/app/js/services/tree.js
@@ -94,39 +94,6 @@ KylinApp.service('GraphService', function () {
                       });
                   }
           });
-
-          if (dimension.derived&&dimension.derived.length)
-          {
-              angular.forEach(dimension.derived, function(derived, index){
-                  for (var i = 0; i < lookup._children.length; i++) {
-                      if(lookup._children[i].name == derived)
-                          break;
-                  }
-                  if(i == lookup._children.length) {
-                    lookup._children.push({
-                          "type": "column",
-                          "name": derived + "(DERIVED)"
-                      });
-                  }
-              });
-          }
-
-          if (dimension.hierarchy)
-          {
-              angular.forEach(dimension.column, function(hierarchy, index){
-                  for (var i = 0; i < lookup._children.length; i++) {
-                      if(lookup._children[i].name == hierarchy)
-                          break;
-                  }
-                  if(i == lookup._children.length) {
-                    lookup._children.push({
-                          "type": "column",
-                          "name": hierarchy + "(HIERARCHY)"
-                      });
-                  }
-              });
-          }
-
         };
       });
         model.graph.columnsCount = 0;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/less/component.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/component.less b/webapp/app/less/component.less
index 7da1b69..cb58e3f 100644
--- a/webapp/app/less/component.less
+++ b/webapp/app/less/component.less
@@ -943,4 +943,7 @@ Angular 1.2.0 Animation
 .abn-tree .indented  {
   font-size: 13px;
   color: #3a87ad;
+}
+.model-design .btn-box-tool{
+  font-size: 13px !important;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/header.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/header.html b/webapp/app/partials/header.html
index cfc1aa2..43bf27d 100644
--- a/webapp/app/partials/header.html
+++ b/webapp/app/partials/header.html
@@ -33,7 +33,7 @@
                 <ul class="nav navbar-nav">
                     <li class="project-cntnr"  style="padding:7px 15px;background-color:#2e8965;" ng-if="userService.isAuthorized()">
                         <select chosen ng-model="projectModel.selectedProject" ng-init="newAccess.permission=permissions.READ.value;"
-                                ng-options="project as project for project in projectModel.projects"
+                                ng-options="project.name as project.name for project in projectModel.projects"
                                 style="width: 150px"
                                 data-placeholder="select a project"
                                 class="chosen-select">

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/login.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/login.html b/webapp/app/partials/login.html
index 22b7a9b..e64f9d5 100644
--- a/webapp/app/partials/login.html
+++ b/webapp/app/partials/login.html
@@ -46,7 +46,7 @@
                                     <span>
 
                                         <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 "
+                                                ng-options="project.name as project.name 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/16b66641/webapp/app/partials/modelDesigner/conditions_settings.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/conditions_settings.html b/webapp/app/partials/modelDesigner/conditions_settings.html
index 7994fa1..308e793 100644
--- a/webapp/app/partials/modelDesigner/conditions_settings.html
+++ b/webapp/app/partials/modelDesigner/conditions_settings.html
@@ -114,7 +114,7 @@
                 <div class="row">
                     <div class="col-xs-12">
                         <ol class="text-info">
-                            <li>Not required,leave as default if this cube always need full build</li>
+                            <li>Not required,leave as default if cube always need full build</li>
                             <li>Partition column will select 'date' or 'string' type column from fact table</li>
                             <li>If column selected,please indicate start date to just pull certain data from source</li>
                         </ol>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/modelDesigner/model_dimensions.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_dimensions.html b/webapp/app/partials/modelDesigner/model_dimensions.html
index cd529d9..62af873 100644
--- a/webapp/app/partials/modelDesigner/model_dimensions.html
+++ b/webapp/app/partials/modelDesigner/model_dimensions.html
@@ -20,7 +20,7 @@
 
 <!-- Dimensions Summary -->
 <div class="dataTables_wrapper form-inline no-footer">
-    <div class="row"  ng-if="state.mode=='view'">
+    <div class="row"  ng-if="state.mode=='view'&&model.dimensions.length > 0">
         <div class="col-xs-6">
             <b>Dimensions</b>
         </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/modelDesigner/model_info.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_info.html b/webapp/app/partials/modelDesigner/model_info.html
index 9b9e786..92c1ef0 100644
--- a/webapp/app/partials/modelDesigner/model_info.html
+++ b/webapp/app/partials/modelDesigner/model_info.html
@@ -29,7 +29,7 @@
                 </label>
                 <div class="col-xs-12 col-sm-6">
                     <input ng-if="state.mode=='edit'" name="project_name" type="text" class="form-control"
-                           ng-model="state.project"/>
+                           ng-model="model.project"/>
                     <span ng-if="state.mode=='view'">
                         {{model.project}}
                     </span>
@@ -43,6 +43,7 @@
                 <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default">
                     <b>Model Name</b>
                 </label>
+
                 <div class="col-xs-12 col-sm-6">
                     <input ng-if="state.mode=='edit'" name="model_name" type="text" class="form-control"
                            ng-model="model.name" required

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/modelDesigner/model_measures.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_measures.html b/webapp/app/partials/modelDesigner/model_measures.html
index 74bf9ae..9451569 100644
--- a/webapp/app/partials/modelDesigner/model_measures.html
+++ b/webapp/app/partials/modelDesigner/model_measures.html
@@ -19,7 +19,7 @@
 <!-- Measures Summary -->
 <div class="dataTables_wrapper form-inline no-footer">
 
-    <table ng-if="state.mode=='view'" class="table table-striped table-hover">
+    <table ng-if="state.mode=='view'&&model.metrics.length > 0" class="table table-striped table-hover">
         <thead>
             <tr>
                 <th>ID</th>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/models/model_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_detail.html b/webapp/app/partials/models/model_detail.html
index a4ae287..6d43210 100644
--- a/webapp/app/partials/models/model_detail.html
+++ b/webapp/app/partials/models/model_detail.html
@@ -17,28 +17,7 @@
 -->
 
 <div ng-controller="CubeModelCtrl" class="nav-tabs-custom">
-    <ul class="nav nav-tabs">
-        <li class="{{(!model.visiblePage || model.visiblePage=='metadata')? 'active':''}}">
-            <a href="" ng-click="model.visiblePage='metadata'">Grid</a>
-        </li>
-        <li class="{{model.visiblePage=='graph'? 'active':''}}">
-            <a href="" ng-click="model.visiblePage='graph';buildGraph(model);$event.stopPropagation();">Visualization</a>
-        </li>
-        <li class="{{model.visiblePage=='json_model'? 'active':''}}"
-            ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission(model, 16) && !newAccess">
-            <a href="" ng-click="model.visiblePage='json_model';">JSON</a>
-        </li>
-    </ul>
-
-    <div class="model-detail" ng-if="!model.visiblePage || model.visiblePage=='metadata'">
-        <div ng-include="'partials/models/model_schema.html'" ng-controller="ModelSchemaCtrl"
-             ng-init="state={mode:'view', modelName:model.name}">
-        </div>
-    </div>
-    <div ng-show="model.visiblePage=='graph'" id="model_graph_{{model.name}}" class="model-detail model_graph">
-    </div>
-    <div ng-show="model.visiblePage=='json_model'" class="model-detail">
-          <pre ng-if="!state.jsonEdit"
-               style="background-color: white;border: 0px">{{angular.toJson(modelJson, true)}}</pre>
+    <div ng-include="'partials/models/model_schema.html'" ng-controller="ModelSchemaCtrl"
+         ng-init="state={mode:'view', modelName:model.name}">
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/models/model_schema.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_schema.html b/webapp/app/partials/models/model_schema.html
index 0cd0b5e..7648f93 100644
--- a/webapp/app/partials/models/model_schema.html
+++ b/webapp/app/partials/models/model_schema.html
@@ -16,9 +16,12 @@
 * limitations under the License.
 -->
 
-<div class="box box-primary">
+<div class="box box-primary model-design">
     <div class="box-header widget-header-blue widget-header-flat">
         <h4 class="box-title text-info">Model Designer</h4>
+        <div class="box-tools pull-right">
+            <a class="btn btn-box-tool" tooltip="Edit Model" href="models/edit/{{model.name}}" data-widget="collapse"><i class="fa fa-edit"></i></a>
+        </div>
     </div>
     <div class="box-body">
         <ng-form name="design_form" ng-submit="">
@@ -40,13 +43,13 @@
             <hr/>
             <div class="wizard-actions">
                 <div class="row">
-                    <div class="col-xs-8">
+                    <div class="col-xs-8" style="display:none;">
                         <p style="color: #808080;text-align: left;"><b>Note:</b> inputs with <span style="color: lightblue">light blue</span> border are mandatory.</p>
                         <div>
                             <a href="models" class="pull-left"><i class="fa fa-arrow-left"></i> Back to My Models</a>
                         </div>
                     </div>
-                    <div class="col-xs-4">
+                    <div class="col-xs-4 pull-right">
                         <button class="btn btn-prev" ng-click="preView()" ng-show="curStep.title!='Model Info'">
                             <i class="ace-icon fa fa-arrow-left"></i>
                             Prev

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/models/models.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/models.html b/webapp/app/partials/models/models.html
index 49343aa..28a8fb3 100644
--- a/webapp/app/partials/models/models.html
+++ b/webapp/app/partials/models/models.html
@@ -17,11 +17,19 @@
 -->
 <div class="row">
     <!--table_tree-->
-    <div class="col-xs-3 overwriteLTE">
-        <div ng-include src="'partials/models/models_tree.html'"></div>
+    <div class="col-xs-3">
+        <tabset>
+            <tab heading="Models" select="toggleTab(true);">
+                <div ng-include src="'partials/models/models_tree.html'"></div>
+            </tab>
+            <tab heading="Data source"  select="toggleTab(false);">
+                <div ng-include src="'partials/tables/source_table_tree.html'"></div>
+            </tab>
+        </tabset>
     </div>
 
-    <div class="col-xs-9">
-        <h3>Model Info</h3>
+    <div class="col-xs-9" style="padding-top:39px;">
+        <div ng-show="showModels" ng-include src="'partials/models/model_detail.html'"></div>
+        <div ng-show="!showModels" ng-include src="'partials/tables/table_detail.html'"></div>
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/tables/source_table_tree.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/source_table_tree.html b/webapp/app/partials/tables/source_table_tree.html
index f381077..627234e 100755
--- a/webapp/app/partials/tables/source_table_tree.html
+++ b/webapp/app/partials/tables/source_table_tree.html
@@ -16,7 +16,7 @@
 * limitations under the License.
 -->
 
-<div class="tree-border">
+<div class="tree-border" ng-controller="SourceMetaCtrl">
     <div class="row">
         <div class="col-xs-7">
             <h3 class="text-info">Tables</h3>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/16b66641/webapp/app/partials/tables/table_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/table_detail.html b/webapp/app/partials/tables/table_detail.html
new file mode 100644
index 0000000..b20825c
--- /dev/null
+++ b/webapp/app/partials/tables/table_detail.html
@@ -0,0 +1,138 @@
+<div  ng-controller="SourceMetaCtrl" class="nav-tabs-custom">
+    <div class="col-xs-9">
+        <h3 class="text-info">Table Schema:{{ tableModel.selectedSrcTable.name}}</h3>
+        <div class="tabbable nav-tabs-custom">
+            <ul class="nav nav-tabs">
+                <li class="active">
+                    <a data-toggle="tab" href="#column">Columns</a>
+                </li>
+                <li>
+                    <a data-toggle="tab" href="#schema">Extend Information</a>
+                </li>
+            </ul>
+            <div class="tab-content">
+                <!--Schema-->
+                <div id="schema" class="tab-pane">
+                    <div ng-if="tableModel.selectedSrcTable.uuid" class="table-responsive">
+                        <table class="table">
+                            <tbody>
+                            <tr>
+                                <th style="width:20%">NAME</th>
+                                <td>{{ tableModel.selectedSrcTable.name}}</td>
+                            </tr>
+                            <tr>
+                                <th>Hive DATABASE</th>
+                                <td>{{tableModel.selectedSrcTable.database}}</td>
+                            </tr>
+                            <tr>
+                                <th>SNAPSHOT TIME</th>
+                                <td>{{tableModel.selectedSrcTable.exd.lastUpdateTime | utcToConfigTimeZone}}</td>
+                            </tr>
+                            <tr>
+                                <th>LOCATION</th>
+                                <td>{{tableModel.selectedSrcTable.exd.location}}</td>
+                            </tr>
+                            <tr>
+                                <th>INPUT FORMAT</th>
+                                <td>{{tableModel.selectedSrcTable.exd.inputformat}}</td>
+                            </tr>
+                            <tr>
+                                <th>OUTPUT FORMAT</th>
+                                <td>{{tableModel.selectedSrcTable.exd.outputformat}}</td>
+                            </tr>
+                            <tr>
+                                <th>OWNER</th>
+                                <td><a href="mailto:{{tableModel.selectedSrcTable.exd.owner}}">{{tableModel.selectedSrcTable.exd.owner}}</a></td>
+                            </tr>
+                            <tr>
+                                <th>TOTAL FILE NUMBER</th>
+                                <td>{{tableModel.selectedSrcTable.exd.totalNumberFiles}}</td>
+                            </tr>
+                            <tr>
+                                <th>TOTAL FILE SIZE</th>
+                                <td>{{tableModel.selectedSrcTable.exd.totalFileSize}}</td>
+                            </tr>
+                            <tr>
+                                <th>PARTITIONED</th>
+                                <td>{{tableModel.selectedSrcTable.exd.partitioned}}</td>
+                            </tr>
+                            <tr>
+                                <th>PARTITION COLUMNS</th>
+                                <td>{{tableModel.selectedSrcTable.exd.partitionColumns}}</td>
+                            </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+                <!--Columns-->
+                <div id="column" class="tab-pane active">
+                    <div class="profile-user-info">
+                        <div>
+                            <label class="table-header-text">Columns</label>
+                            <span class="input-icon form-search nav-search pull-right">
+                                <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="columnName"/>
+                                <i class="ace-icon fa fa-search nav-search-icon"></i>
+                            </span>
+                        </div>
+                        <div class="space-6"></div>
+                        <div ng-if="(tableModel.selectedSrcTable.columns | filter: columnName).length>0">
+                            <table class="table table-hover table-striped list">
+                                <thead>
+                                <tr style="cursor: pointer">
+                                    <th ng-repeat="theaditem in tableConfig.theaditems"
+                                        ng-click="state.filterAttr= theaditem.attr;state.reverseColumn=theaditem.attr;state.filterReverse=!state.filterReverse;">
+                                        {{theaditem.name}}
+                                        <i ng-if="state.reverseColumn!= theaditem.attr"
+                                           class="fa fa-unsorted"></i>
+                                        <i ng-if="state.reverseColumn== theaditem.attr && !state.filterReverse"
+                                           class="fa fa-sort-asc"></i>
+                                        <i ng-if="state.reverseColumn== theaditem.attr && state.filterReverse"
+                                           class="fa fa-sort-desc"></i>
+                                    </th>
+                                </tr>
+                                </thead>
+
+                                <tr ng-repeat="column in tableModel.selectedSrcTable.columns | filter: columnName | orderObjectBy:state.filterAttr:state.filterReverse">
+                                    <td style="{{(tableModel.selectedSrcTable.selectedSrcColumn.id == column.id)? 'background-color:#EBF9FE':''}}">
+                                        {{ column.id}}
+                                    </td>
+                                    <td style="{{(tableModel.selectedSrcTable.selectedSrcColumn.id == column.id)? 'background-color:#EBF9FE':''}}">
+                                        {{ column.name}}
+                                    </td>
+                                    <td style="{{(tableModel.selectedSrcTable.selectedSrcColumn.id == column.id)? 'background-color:#EBF9FE':''}}">
+                                        {{ column.datatype}}
+                                    </td>
+                                    <td style="{{(tableModel.selectedSrcTable.selectedSrcColumn.id == column.id)? 'background-color:#EBF9FE':''}}">
+                                        <!--{{ tableModel.selectedSrcTable.cardinality[column.name]}}-->
+                                        {{column.cardinality}}
+                                    </td>
+                                </tr>
+                            </table>
+                        </div>
+                        <div ng-if="(tableModel.selectedSrcTable.columns | filter: columnName).length == 0" no-result
+                             text="No Matched Table Column."></div>
+                        <div ng-if="!!!tableModel.selectedSrcTable.uuid">
+                            <div no-result text="No Table Selected."></div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <script type="text/ng-template" id="addHiveTable.html">
+        <div class="modal-header">
+            <h4>Load Hive Table Metadata</h4>
+        </div>
+        <div class="modal-body">
+            <span><strong>Project: </strong>{{ $parent.projectName!=null?$parent.projectName:'NULL'}}</span>
+            <label for="tables"> Table Names:(Seperate with comma)</label>
+            <textarea ng-model="$parent.tableNames" class="form-control" id="tables"
+                      placeholder="table1,table2  By default,system will choose 'Default' as database,you can specify database like this 'database.table'"></textarea>
+        </div>
+        <div class="modal-footer">
+            <button class="btn btn-primary" ng-click="add()">Sync</button>
+            <button class="btn btn-primary" ng-click="cancel()">Cancel</button>
+        </div>
+    </script>
+</div>