You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by zh...@apache.org on 2015/10/22 12:06:55 UTC

[3/5] incubator-kylin git commit: KYLIN-1041, Streaming UI

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/cubeEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js
index 2dea4f4..2920458 100755
--- a/webapp/app/js/controllers/cubeEdit.js
+++ b/webapp/app/js/controllers/cubeEdit.js
@@ -14,629 +14,785 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-*/
+ */
 
 'use strict';
 
 
-KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $location, $templateCache, $interpolate, MessageService, TableService, CubeDescService, CubeService, loadingRequest, SweetAlert,$log,cubeConfig,CubeDescModel,MetaModel,TableModel,ModelDescService,modelsManager,cubesManager,ProjectModel) {
-    $scope.cubeConfig = cubeConfig;
+KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $location, $templateCache, $interpolate, MessageService, TableService, CubeDescService, CubeService, loadingRequest, SweetAlert, $log, cubeConfig, CubeDescModel, MetaModel, TableModel, ModelDescService, modelsManager, cubesManager, ProjectModel, StreamingModel, StreamingService) {
+  var STREAMING_SUFFIX = "_streaming";
+  $scope.cubeConfig = cubeConfig;
 
-  $scope.metaModel ={};
+  $scope.metaModel = {};
   $scope.modelsManager = modelsManager;
 
-    //add or edit ?
-    var absUrl = $location.absUrl();
-    $scope.cubeMode = absUrl.indexOf("/cubes/add")!=-1?'addNewCube':absUrl.indexOf("/cubes/edit")!=-1?'editExistCube':'default';
+  //add or edit ?
+  var absUrl = $location.absUrl();
+  $scope.cubeMode = absUrl.indexOf("/cubes/add") != -1 ? 'addNewCube' : absUrl.indexOf("/cubes/edit") != -1 ? 'editExistCube' : 'default';
 
-  if($scope.cubeMode=="addNewCube"&&!ProjectModel.getSelectedProject()){
+  if ($scope.cubeMode == "addNewCube" && !ProjectModel.getSelectedProject()) {
     SweetAlert.swal('Oops...', 'Please select your project first.', 'warning');
     $location.path("/models");
     return;
   }
 
 
-
   $scope.getColumnsByTable = function (tableName) {
-        var temp = [];
-        angular.forEach(TableModel.selectProjectTables, function (table) {
-            if (table.name == tableName) {
-                temp = table.columns;
-            }
-        });
-        return temp;
-    };
+    var temp = [];
+    angular.forEach(TableModel.selectProjectTables, function (table) {
+      if (table.name == tableName) {
+        temp = table.columns;
+      }
+    });
+    return temp;
+  };
 
-    $scope.getDimColumnsByTable = function (tableName) {
-        if(!tableName){
-            return [];
-        }
-        var tableColumns = $scope.getColumnsByTable(tableName);
-        var tableDim = _.find($scope.metaModel.model.dimensions,function(dimension){return dimension.table == tableName});
-        var tableDimColumns = tableDim.columns;
-        var avaColObject = _.filter(tableColumns,function(col){
-            return tableDimColumns.indexOf(col.name)!=-1;
-        });
-        return avaColObject;
-    };
+  $scope.getDimColumnsByTable = function (tableName) {
+    if (!tableName) {
+      return [];
+    }
+    var tableColumns = $scope.getColumnsByTable(tableName);
+    var tableDim = _.find($scope.metaModel.model.dimensions, function (dimension) {
+      return dimension.table == tableName
+    });
+    var tableDimColumns = tableDim.columns;
+    var avaColObject = _.filter(tableColumns, function (col) {
+      return tableDimColumns.indexOf(col.name) != -1;
+    });
+    return avaColObject;
+  };
 
-    $scope.getMetricColumnsByTable = function (tableName) {
-        if(!tableName){
-            return [];
-        }
-        var tableColumns = $scope.getColumnsByTable(tableName);
-        var tableMetrics = $scope.metaModel.model.metrics;
-        var avaColObject = _.filter(tableColumns,function(col){
-            return tableMetrics.indexOf(col.name)!=-1;
-        });
-        return avaColObject;
-    };
+  $scope.getMetricColumnsByTable = function (tableName) {
+    if (!tableName) {
+      return [];
+    }
+    var tableColumns = $scope.getColumnsByTable(tableName);
+    var tableMetrics = $scope.metaModel.model.metrics;
+    var avaColObject = _.filter(tableColumns, function (col) {
+      return tableMetrics.indexOf(col.name) != -1;
+    });
+    return avaColObject;
+  };
+
+  $scope.getColumnType = function (_column, table) {
+    var columns = $scope.getColumnsByTable(table);
+    var type;
+    angular.forEach(columns, function (column) {
+      if (_column === column.name) {
+        type = column.datatype;
+        return;
+      }
+    });
+    return type;
+  };
+
+  var ColFamily = function () {
+    var index = 1;
+    return function () {
+      var newColFamily =
+      {
+        "name": "f" + index,
+        "columns": [
+          {
+            "qualifier": "m",
+            "measure_refs": []
+          }
+        ]
+      };
+      index += 1;
 
-    $scope.getColumnType = function (_column,table){
-        var columns = $scope.getColumnsByTable(table);
-        var type;
-        angular.forEach(columns,function(column){
-            if(_column === column.name){
-                type = column.datatype;
-                return;
-            }
-        });
-        return type;
-    };
+      return newColFamily;
+    }
+  };
 
-    var ColFamily = function () {
-        var index = 1;
-        return function () {
-            var newColFamily =
-            {
-                "name": "f" + index,
-                "columns": [
-                    {
-                        "qualifier": "m",
-                        "measure_refs": []
-                    }
-                ]
-            };
-            index += 1;
-
-            return  newColFamily;
+
+  // ~ Define data
+  $scope.state = {
+    "cubeSchema": "",
+    "mode": 'edit'
+  };
+
+  $scope.cubeState={
+    "isStreaming": false
+  }
+
+  //fetch cube info and model info in edit model
+  // ~ init
+  if ($scope.isEdit = !!$routeParams.cubeName) {
+    CubeDescService.query({cube_name: $routeParams.cubeName}, function (detail) {
+      if (detail.length > 0) {
+        $scope.cubeMetaFrame = detail[0];
+        $scope.metaModel = {};
+
+        //get model from API when page refresh
+        if (!modelsManager.getModels().length) {
+          ModelDescService.query({model_name: $scope.cubeMetaFrame.model_name}, function (_model) {
+            $scope.metaModel.model = _model;
+          });
         }
-    };
+        $scope.metaModel.model = modelsManager.getModel($scope.cubeMetaFrame.model_name);
 
+        $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
 
-    // ~ Define data
-    $scope.state = {
-        "cubeSchema": "",
-        "mode":'edit'
-    };
+        StreamingService.getConfig({cubeName:$scope.cubeMetaFrame.name}, function (kfkConfigs) {
 
-    //fetch cube info and model info in edit model
-    // ~ init
-    if ($scope.isEdit = !!$routeParams.cubeName) {
-        CubeDescService.query({cube_name: $routeParams.cubeName}, function (detail) {
-            if (detail.length > 0) {
-                $scope.cubeMetaFrame = detail[0];
-                $scope.metaModel = {};
-
-                //get model from API when page refresh
-                if(!modelsManager.getModels().length){
-                    ModelDescService.query({model_name: $scope.cubeMetaFrame.model_name}, function (_model) {
-                        $scope.metaModel.model = _model;
-                    });
-                }
-                $scope.metaModel.model=modelsManager.getModel($scope.cubeMetaFrame.model_name);
-
-                $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
-            }
-        });
+          if(!!kfkConfigs[0]){
+            $scope.cubeState.isStreaming = true;
+          }
+          $scope.streamingMeta = kfkConfigs[0];
+          StreamingService.getKfkConfig({kafkaConfigName:$scope.streamingMeta.name}, function (streamings) {
+            $scope.kafkaMeta = streamings[0];
+          })
+        })
+      }
+    });
 
-    } else {
+
+
+  } else {
 //        $scope.cubeMetaFrame = CubeDescModel.createNew();
-        $scope.cubeMetaFrame = CubeDescModel.createNew();
-        $scope.metaModel ={
-            model : modelsManager.getModel($scope.cubeMetaFrame.model_name)
-        }
-        //$scope.cubeMetaFrame.model_name = modelName;
-        $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
+    $scope.cubeMetaFrame = CubeDescModel.createNew();
+    $scope.metaModel = {
+      model: modelsManager.getModel($scope.cubeMetaFrame.model_name)
     }
+    //$scope.cubeMetaFrame.model_name = modelName;
+    $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
 
+    $scope.streamingMeta = StreamingModel.createStreamingConfig();
+    $scope.kafkaMeta = StreamingModel.createKafkaConfig();
 
-    $scope.prepareCube = function () {
-        // generate column family
-        generateColumnFamily();
-        //generate rowkey TODO remove after refactor
-        reGenerateRowKey();
+  }
 
 
-        if ($scope.metaModel.model.partition_desc.partition_date_column&&($scope.metaModel.model.partition_desc.partition_date_start|$scope.metaModel.model.partition_desc.partition_date_start==0)) {
-            var dateStart = new Date($scope.metaModel.model.partition_desc.partition_date_start);
-            dateStart = (dateStart.getFullYear() + "-" + (dateStart.getMonth() + 1) + "-" + dateStart.getDate());
-            //switch selected time to utc timestamp
-            $scope.metaModel.model.partition_desc.partition_date_start = new Date(moment.utc(dateStart, "YYYY-MM-DD").format()).getTime();
+  $scope.prepareCube = function () {
+    //generate column family
+    generateColumnFamily();
+    //generate rowkey
+    reGenerateRowKey();
 
+    if ($scope.metaModel.model.partition_desc.partition_date_column && ($scope.metaModel.model.partition_desc.partition_date_start | $scope.metaModel.model.partition_desc.partition_date_start == 0)) {
+      var dateStart = new Date($scope.metaModel.model.partition_desc.partition_date_start);
+      dateStart = (dateStart.getFullYear() + "-" + (dateStart.getMonth() + 1) + "-" + dateStart.getDate());
+      //switch selected time to utc timestamp
+      $scope.metaModel.model.partition_desc.partition_date_start = new Date(moment.utc(dateStart, "YYYY-MM-DD").format()).getTime();
 
-            if($scope.metaModel.model.partition_desc.partition_date_column.indexOf(".")==-1){
-            $scope.metaModel.model.partition_desc.partition_date_column=$scope.metaModel.model.fact_table+"."+$scope.metaModel.model.partition_desc.partition_date_column;
-            }
 
-        }
-        //use cubedesc name as model name
-        if($scope.metaModel.model.name===""||angular.isUndefined($scope.metaModel.model.name)){
-            $scope.metaModel.model.name = $scope.cubeMetaFrame.name;
-        }
+      if ($scope.metaModel.model.partition_desc.partition_date_column.indexOf(".") == -1) {
+        $scope.metaModel.model.partition_desc.partition_date_column = $scope.metaModel.model.fact_table + "." + $scope.metaModel.model.partition_desc.partition_date_column;
+      }
 
-        //set model ref for cubeDesc
-        if($scope.cubeMetaFrame.model_name===""||angular.isUndefined($scope.cubeMetaFrame.model_name)){
-            $scope.cubeMetaFrame.model_name = $scope.cubeMetaFrame.name;
-        }
+    }
+    //use cubedesc name as model name
+    if ($scope.metaModel.model.name === "" || angular.isUndefined($scope.metaModel.model.name)) {
+      $scope.metaModel.model.name = $scope.cubeMetaFrame.name;
+    }
 
-        $scope.state.project = ProjectModel.getSelectedProject();
+    //set model ref for cubeDesc
+    if ($scope.cubeMetaFrame.model_name === "" || angular.isUndefined($scope.cubeMetaFrame.model_name)) {
+      $scope.cubeMetaFrame.model_name = $scope.cubeMetaFrame.name;
+    }
+
+    $scope.state.project = ProjectModel.getSelectedProject();
 //        delete $scope.cubeMetaFrame.project;
-        $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
-    };
+    $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
 
-    $scope.cubeResultTmpl = function (notification) {
-        // Get the static notification template.
-        var tmpl = notification.type == 'success' ? 'cubeResultSuccess.html' : 'cubeResultError.html';
-        return $interpolate($templateCache.get(tmpl))(notification);
-    };
+    //streaming meta
+    if($scope.cubeState.isStreaming == true){
+      $scope.streamingMeta.cubeName = $scope.cubeMetaFrame.name;
+      $scope.streamingMeta.name = $scope.cubeMetaFrame.name+STREAMING_SUFFIX;
+      $scope.kafkaMeta.name = $scope.cubeMetaFrame.name+STREAMING_SUFFIX;
+    }
 
-    $scope.saveCube = function () {
 
-        try {
-            angular.fromJson($scope.state.cubeSchema);
-        } catch (e) {
-            SweetAlert.swal('Oops...', 'Invalid cube json format..', 'error');
-            return;
-        }
 
-        SweetAlert.swal({
-            title: '',
-            text: 'Are you sure to save the cube ?',
-            type: '',
-            showCancelButton: true,
-            confirmButtonColor: '#DD6B55',
-            confirmButtonText: "Yes",
-            closeOnConfirm: true
-        }, function(isConfirm) {
-            if(isConfirm){
-                loadingRequest.show();
-
-                if ($scope.isEdit) {
-                    CubeService.update({}, {cubeDescData: $scope.state.cubeSchema, cubeName: $routeParams.cubeName, project: $scope.state.project}, function (request) {
-                        if (request.successful) {
-                            $scope.state.cubeSchema = request.cubeDescData;
-                            SweetAlert.swal('', 'Updated the cube successfully.', 'success');
-                            $location.path("/models");
-                        } else {
-                            $scope.saveCubeRollBack();
-                            $scope.cubeMetaFrame.project = $scope.state.project;
-                                var message =request.message;
-                                var msg = !!(message) ? message : 'Failed to take action.';
-                                MessageService.sendMsg($scope.cubeResultTmpl({'text':msg,'schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        }
-                        //end loading
-                        loadingRequest.hide();
-                    }, function (e) {
-                        $scope.saveCubeRollBack();
-
-                        if(e.data&& e.data.exception){
-                            var message =e.data.exception;
-                            var msg = !!(message) ? message : 'Failed to take action.';
-                            MessageService.sendMsg($scope.cubeResultTmpl({'text':msg,'schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        } else {
-                            MessageService.sendMsg($scope.cubeResultTmpl({'text':'Failed to take action.','schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        }
-                        loadingRequest.hide();
-                    });
-                } else {
-                    CubeService.save({}, {cubeDescData: $scope.state.cubeSchema, project: $scope.state.project}, function (request) {
-                        if(request.successful) {
-                            $scope.state.cubeSchema = request.cubeDescData;
-
-                            SweetAlert.swal('', 'Created the cube successfully.', 'success');
-                            $location.path("/models");
-                            //location.reload();
-
-                        } else {
-                            $scope.saveCubeRollBack();
-                            $scope.cubeMetaFrame.project = $scope.state.project;
-                            var message =request.message;
-                            var msg = !!(message) ? message : 'Failed to take action.';
-                            MessageService.sendMsg($scope.cubeResultTmpl({'text':msg,'schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        }
-
-                        //end loading
-                        loadingRequest.hide();
-                    }, function (e) {
-                        $scope.saveCubeRollBack();
-
-                        if (e.data && e.data.exception) {
-                            var message =e.data.exception;
-                            var msg = !!(message) ? message : 'Failed to take action.';
-                            MessageService.sendMsg($scope.cubeResultTmpl({'text':msg,'schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        } else {
-                            MessageService.sendMsg($scope.cubeResultTmpl({'text':"Failed to take action.",'schema':$scope.state.cubeSchema}), 'error', {}, true, 'top_center');
-                        }
-                        //end loading
-                        loadingRequest.hide();
-
-                    });
-                }
-            }
-            else{
-                $scope.saveCubeRollBack();
-            }
-        });
-    };
+  };
 
-//    reverse the date
-    $scope.saveCubeRollBack = function (){
-        if($scope.metaModel.model&&($scope.metaModel.model.partition_desc.partition_date_start||$scope.metaModel.model.partition_desc.partition_date_start==0))
-        {
-            $scope.metaModel.model.partition_desc.partition_date_start+=new Date().getTimezoneOffset()*60000;
-        }
+  $scope.cubeResultTmpl = function (notification) {
+    // Get the static notification template.
+    var tmpl = notification.type == 'success' ? 'cubeResultSuccess.html' : 'cubeResultError.html';
+    return $interpolate($templateCache.get(tmpl))(notification);
+  };
+
+  $scope.saveCube = function () {
+
+    try {
+      angular.fromJson($scope.state.cubeSchema);
+    } catch (e) {
+      SweetAlert.swal('Oops...', 'Invalid cube json format..', 'error');
+      return;
     }
 
-    $scope.updateMandatory = function(rowkey_column){
-        if(!rowkey_column.mandatory){
-            angular.forEach($scope.cubeMetaFrame.rowkey.aggregation_groups, function (group, index) {
-                   var index = group.indexOf(rowkey_column.column);
-                   if(index>-1){
-                       group.splice(index,1);
-                   }
-            });
-        }
+    if (!$scope.cubeState.isStreaming) {
+      $scope.state.streamingCube = false;
+    } else {
+      $scope.state.streamingCube = true;
+      $scope.state.streamingMeta = angular.toJson($scope.streamingMeta, true);
+      $scope.state.kafkaMeta = angular.toJson($scope.kafkaMeta, true);
     }
 
-    function reGenerateRowKey(){
-        $log.log("reGen rowkey & agg group");
-        var fk_pk = {};
-        var tmpRowKeyColumns = [];
-        var tmpAggregationItems = [];//put all aggregation item
-        var hierarchyItemArray = [];//put all hierarchy items
-        angular.forEach($scope.cubeMetaFrame.dimensions, function (dimension, index) {
-
-          // build fk_pk map
-          angular.forEach($scope.metaModel.model.lookups, function (_lookup, index) {
-            for (var i = 0; i < _lookup.join.foreign_key.length; i++) {
-              fk_pk[_lookup.join.primary_key[i]] = _lookup.join.foreign_key[i];
+
+    SweetAlert.swal({
+      title: '',
+      text: 'Are you sure to save the cube ?',
+      type: '',
+      showCancelButton: true,
+      confirmButtonColor: '#DD6B55',
+      confirmButtonText: "Yes",
+      closeOnConfirm: true
+    }, function (isConfirm) {
+      if (isConfirm) {
+        loadingRequest.show();
+
+        if ($scope.isEdit) {
+          CubeService.update({}, {
+            cubeDescData: $scope.state.cubeSchema,
+            cubeName: $routeParams.cubeName,
+            project: $scope.state.project,
+            streamingCube: $scope.state.streamingCube,
+            streamingData: $scope.state.streamingMeta,
+            kafkaData: $scope.state.kafkaMeta
+          }, function (request) {
+            if (request.successful) {
+              $scope.state.cubeSchema = request.cubeDescData;
+              SweetAlert.swal('', 'Updated the cube successfully.', 'success');
+              $location.path("/models");
+            } else {
+              $scope.saveCubeRollBack();
+              $scope.cubeMetaFrame.project = $scope.state.project;
+              var message = request.message;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': msg,
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
+            }
+            //end loading
+            loadingRequest.hide();
+          }, function (e) {
+            $scope.saveCubeRollBack();
+
+            if (e.data && e.data.exception) {
+              var message = e.data.exception;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': msg,
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
+            } else {
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': 'Failed to take action.',
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
             }
+            loadingRequest.hide();
           });
+        } else {
+          CubeService.save({}, {
+            cubeDescData: $scope.state.cubeSchema,
+            project: $scope.state.project,
+            streamingCube: $scope.state.streamingCube,
+            streamingData: $scope.state.streamingMeta,
+            kafkaData: $scope.state.kafkaMeta
+          }, function (request) {
+            if (request.successful) {
+              $scope.state.cubeSchema = request.cubeDescData;
+              SweetAlert.swal('', 'Created the cube successfully.', 'success');
+              $location.path("/models");
+              //location.reload();
+
+            } else {
+              $scope.saveCubeRollBack();
+              $scope.cubeMetaFrame.project = $scope.state.project;
+              var message = request.message;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': msg,
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
+            }
 
-           //derived column
-            if(dimension.derived&&dimension.derived.length){
-                var lookup = _.find($scope.metaModel.model.lookups,function(lookup){return lookup.table==dimension.table});
-                angular.forEach(lookup.join.foreign_key, function (fk, index) {
-                    for (var i = 0; i < tmpRowKeyColumns.length; i++) {
-                        if(tmpRowKeyColumns[i].column == fk)
-                            break;
-                    }
-                    // push to array if no duplicate value
-                    if(i == tmpRowKeyColumns.length) {
-                        tmpRowKeyColumns.push({
-                            "column": fk,
-                            "length": 0,
-                            "dictionary": "true",
-                            "mandatory": false
-                        });
-
-                        tmpAggregationItems.push(fk);
-                    }
-                })
-
+            //end loading
+            loadingRequest.hide();
+          }, function (e) {
+            $scope.saveCubeRollBack();
+
+            if (e.data && e.data.exception) {
+              var message = e.data.exception;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': msg,
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
+            } else {
+              MessageService.sendMsg($scope.cubeResultTmpl({
+                'text': "Failed to take action.",
+                'schema': $scope.state.cubeSchema
+              }), 'error', {}, true, 'top_center');
             }
-            //normal column
-            else if (dimension.column&&!dimension.hierarchy&&dimension.column.length==1) {
-                for (var i = 0; i < tmpRowKeyColumns.length; i++) {
-                    if(tmpRowKeyColumns[i].column == dimension.column[0])
-                        break;
-                }
-                if(i == tmpRowKeyColumns.length) {
-                    tmpRowKeyColumns.push({
-                        "column": dimension.column[0],
-                        "length": 0,
-                        "dictionary": "true",
-                        "mandatory": false
-                    });
-                    tmpAggregationItems.push(dimension.column[0]);
-                }
+            //end loading
+            loadingRequest.hide();
+
+          });
+        }
+      }
+      else {
+        $scope.saveCubeRollBack();
+      }
+    });
+  };
+
+  //save streaming
+  $scope.postData = {};
+  $scope.saveStreaming = function () {
+    $scope.kafkaMeta.name = $scope.streamingMeta.name;
+
+    $scope.postData.streamingMeta = angular.toJson($scope.streamingMeta, true);
+    $scope.postData.kafkaMeta = angular.toJson($scope.kafkaMeta, true);
+    SweetAlert.swal({
+      title: '',
+      text: 'Are you sure to save Streaming ?',
+      type: '',
+      showCancelButton: true,
+      confirmButtonColor: '#DD6B55',
+      confirmButtonText: "Yes",
+      closeOnConfirm: true
+    }, function (isConfirm) {
+      if (isConfirm) {
+        loadingRequest.show();
+
+        if ($scope.modelMode == "editExistStreaming") {
+          StreamingService.update({}, {
+            project: $scope.projectModel.selectedProject,
+            streamingConfig: $scope.postData.streamingMeta,
+            kafkaConfig: $scope.postData.kafkaMeta
+          }, function (request) {
+            if (request.successful) {
+              SweetAlert.swal('', 'Updated the streaming successfully.', 'success');
+              $location.path("/models");
+            } else {
+              var message = request.message;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.streamingResultTmpl({
+                'text': msg,
+                'streamingSchema': $scope.postData.streamingMeta,
+                'kfkSchema': $scope.postData.kafkaMeta
+              }), 'error', {}, true, 'top_center');
             }
-            // hierarchy
-            if(dimension.hierarchy && dimension.column.length){
-                var hierarchyUnit = [];
-                angular.forEach(dimension.column, function (hier_column, index) {
-
-                  //use fk instead of fk as rowkey and aggregation item in hierarchy
-                  if (hier_column in fk_pk) {
-                    hier_column = fk_pk[hier_column];
-                  }
-
-                    for (var i = 0; i < tmpRowKeyColumns.length; i++) {
-                        if(tmpRowKeyColumns[i].column == hier_column)
-                            break;
-                    }
-                    if(i == tmpRowKeyColumns.length) {
-                        tmpRowKeyColumns.push({
-                            "column": hier_column,
-                            "length": 0,
-                            "dictionary": "true",
-                            "mandatory": false
-                        });
-                        tmpAggregationItems.push(hier_column);
-                    }
-                    if(hierarchyUnit.indexOf(hier_column)==-1){
-                      hierarchyUnit.push(hier_column);
-                    }
-                });
-              if(hierarchyUnit.length){
-                hierarchyItemArray.push(hierarchyUnit);
-              }
+            loadingRequest.hide();
+          })
+        } else {
+          StreamingService.save({}, {
+            project: $scope.projectModel.selectedProject,
+            streamingConfig: $scope.postData.streamingMeta,
+            kafkaConfig: $scope.postData.kafkaMeta
+          }, function (request) {
+            if (request.successful) {
+              SweetAlert.swal('', 'Created the streaming successfully.', 'success');
+              $location.path("/models");
+            } else {
+              var message = request.message;
+              var msg = !!(message) ? message : 'Failed to take action.';
+              MessageService.sendMsg($scope.streamingResultTmpl({
+                'text': msg,
+                'streamingSchema': $scope.postData.streamingMeta,
+                'kfkSchema': $scope.postData.kafkaMeta
+              }), 'error', {}, true, 'top_center');
             }
+            loadingRequest.hide();
+          })
+        }
 
-        });
+      }
+    });
 
 
-        //rm mandatory column from aggregation item
-        angular.forEach($scope.cubeMetaFrame.rowkey.rowkey_columns,function(value,index){
-                if(value.mandatory){
-                    tmpAggregationItems = _.filter(tmpAggregationItems,function(item){
-                           return item!=value.column;
-                    });
-                }
-        });
+  }
 
-        var rowkeyColumns = $scope.cubeMetaFrame.rowkey.rowkey_columns;
-        var newRowKeyColumns = sortSharedData(rowkeyColumns,tmpRowKeyColumns);
-        var increasedColumns = increasedColumn(rowkeyColumns,tmpRowKeyColumns);
-        newRowKeyColumns = newRowKeyColumns.concat(increasedColumns);
-
-        //! here get the latest rowkey_columns
-        $scope.cubeMetaFrame.rowkey.rowkey_columns = newRowKeyColumns;
-
-        if($scope.cubeMode==="editExistCube") {
-            var aggregationGroups = $scope.cubeMetaFrame.rowkey.aggregation_groups;
-            // rm unused item from group,will only rm when [edit] dimension
-            angular.forEach(aggregationGroups, function (group, index) {
-                if (group) {
-                    for (var j = 0; j < group.length; j++) {
-                        var elemStillExist = false;
-                        for (var k = 0; k < tmpAggregationItems.length; k++) {
-                            if (group[j] == tmpAggregationItems[k]) {
-                                elemStillExist = true;
-                                break;
-                            }
-                        }
-                        if (!elemStillExist) {
-                            group.splice(j, 1);
-                            j--;
-                        }
-                    }
-                    if (!group.length) {
-                        aggregationGroups.splice(index, 1);
-                        index--;
-                    }
-                }
-                else {
-                    aggregationGroups.splice(index, 1);
-                    index--;
-                }
-            });
+
+//    reverse the date
+  $scope.saveCubeRollBack = function () {
+    if ($scope.metaModel.model && ($scope.metaModel.model.partition_desc.partition_date_start || $scope.metaModel.model.partition_desc.partition_date_start == 0)) {
+      $scope.metaModel.model.partition_desc.partition_date_start += new Date().getTimezoneOffset() * 60000;
+    }
+  }
+
+  $scope.updateMandatory = function (rowkey_column) {
+    if (!rowkey_column.mandatory) {
+      angular.forEach($scope.cubeMetaFrame.rowkey.aggregation_groups, function (group, index) {
+        var index = group.indexOf(rowkey_column.column);
+        if (index > -1) {
+          group.splice(index, 1);
         }
+      });
+    }
+  }
 
-        if($scope.cubeMode==="addNewCube"){
+  function reGenerateRowKey() {
+    $log.log("reGen rowkey & agg group");
+    var fk_pk = {};
+    var tmpRowKeyColumns = [];
+    var tmpAggregationItems = [];//put all aggregation item
+    var hierarchyItemArray = [];//put all hierarchy items
+    angular.forEach($scope.cubeMetaFrame.dimensions, function (dimension, index) {
+
+      // build fk_pk map
+      angular.forEach($scope.metaModel.model.lookups, function (_lookup, index) {
+        for (var i = 0; i < _lookup.join.foreign_key.length; i++) {
+          fk_pk[_lookup.join.primary_key[i]] = _lookup.join.foreign_key[i];
+        }
+      });
 
-          if(!tmpAggregationItems.length) {
-              $scope.cubeMetaFrame.rowkey.aggregation_groups=[];
-              return;
+      //derived column
+      if (dimension.derived && dimension.derived.length) {
+        var lookup = _.find($scope.metaModel.model.lookups, function (lookup) {
+          return lookup.table == dimension.table
+        });
+        angular.forEach(lookup.join.foreign_key, function (fk, index) {
+          for (var i = 0; i < tmpRowKeyColumns.length; i++) {
+            if (tmpRowKeyColumns[i].column == fk)
+              break;
           }
-
-            var newUniqAggregationItem = [];
-            angular.forEach(tmpAggregationItems, function (item, index) {
-                if(newUniqAggregationItem.indexOf(item)==-1){
-                    newUniqAggregationItem.push(item);
-                }
+          // push to array if no duplicate value
+          if (i == tmpRowKeyColumns.length) {
+            tmpRowKeyColumns.push({
+              "column": fk,
+              "length": 0,
+              "dictionary": "true",
+              "mandatory": false
             });
 
-          //distinct hierarchyItem
-          var hierarchyItems = hierarchyItemArray.join().split(",");
-          var _hierarchyItems = [];
-          angular.forEach(hierarchyItems, function (item, index) {
-            if (_hierarchyItems.indexOf(item) == -1) {
-              _hierarchyItems.push(item);
-            }
+            tmpAggregationItems.push(fk);
+          }
+        })
+
+      }
+      //normal column
+      else if (dimension.column && !dimension.hierarchy && dimension.column.length == 1) {
+        for (var i = 0; i < tmpRowKeyColumns.length; i++) {
+          if (tmpRowKeyColumns[i].column == dimension.column[0])
+            break;
+        }
+        if (i == tmpRowKeyColumns.length) {
+          tmpRowKeyColumns.push({
+            "column": dimension.column[0],
+            "length": 0,
+            "dictionary": "true",
+            "mandatory": false
           });
-          hierarchyItems = _hierarchyItems;
-
-          var unHierarchyItems = increasedData(hierarchyItems,newUniqAggregationItem);
-          //hierarchyItems
-          var increasedDataGroups = sliceGroupItemToGroups(unHierarchyItems);
-          if(!hierarchyItemArray.length){
-              $scope.cubeMetaFrame.rowkey.aggregation_groups = increasedDataGroups;
-              return;
-          };
-
-          var lastAggregationGroup = increasedDataGroups.length===0?[]:increasedDataGroups[increasedDataGroups.length-1];
-
-          if(lastAggregationGroup.length<10){
-            if(lastAggregationGroup.length+hierarchyItemArray.length<=10){
-              lastAggregationGroup = lastAggregationGroup.concat(hierarchyItems);
-              if(increasedDataGroups.length==0){
-                //case only hierarchy
-                increasedDataGroups[0]=lastAggregationGroup;
-              }else{
-                increasedDataGroups[increasedDataGroups.length-1]=lastAggregationGroup;
+          tmpAggregationItems.push(dimension.column[0]);
+        }
+      }
+      // hierarchy
+      if (dimension.hierarchy && dimension.column.length) {
+        var hierarchyUnit = [];
+        angular.forEach(dimension.column, function (hier_column, index) {
+
+          //use fk instead of fk as rowkey and aggregation item in hierarchy
+          if (hier_column in fk_pk) {
+            hier_column = fk_pk[hier_column];
+          }
+
+          for (var i = 0; i < tmpRowKeyColumns.length; i++) {
+            if (tmpRowKeyColumns[i].column == hier_column)
+              break;
+          }
+          if (i == tmpRowKeyColumns.length) {
+            tmpRowKeyColumns.push({
+              "column": hier_column,
+              "length": 0,
+              "dictionary": "true",
+              "mandatory": false
+            });
+            tmpAggregationItems.push(hier_column);
+          }
+          if (hierarchyUnit.indexOf(hier_column) == -1) {
+            hierarchyUnit.push(hier_column);
+          }
+        });
+        if (hierarchyUnit.length) {
+          hierarchyItemArray.push(hierarchyUnit);
+        }
+      }
+
+    });
+
+
+    //rm mandatory column from aggregation item
+    angular.forEach($scope.cubeMetaFrame.rowkey.rowkey_columns, function (value, index) {
+      if (value.mandatory) {
+        tmpAggregationItems = _.filter(tmpAggregationItems, function (item) {
+          return item != value.column;
+        });
+      }
+    });
+
+    var rowkeyColumns = $scope.cubeMetaFrame.rowkey.rowkey_columns;
+    var newRowKeyColumns = sortSharedData(rowkeyColumns, tmpRowKeyColumns);
+    var increasedColumns = increasedColumn(rowkeyColumns, tmpRowKeyColumns);
+    newRowKeyColumns = newRowKeyColumns.concat(increasedColumns);
+
+    //! here get the latest rowkey_columns
+    $scope.cubeMetaFrame.rowkey.rowkey_columns = newRowKeyColumns;
+
+    if ($scope.cubeMode === "editExistCube") {
+      var aggregationGroups = $scope.cubeMetaFrame.rowkey.aggregation_groups;
+      // rm unused item from group,will only rm when [edit] dimension
+      angular.forEach(aggregationGroups, function (group, index) {
+        if (group) {
+          for (var j = 0; j < group.length; j++) {
+            var elemStillExist = false;
+            for (var k = 0; k < tmpAggregationItems.length; k++) {
+              if (group[j] == tmpAggregationItems[k]) {
+                elemStillExist = true;
+                break;
               }
             }
-            else{
-                var cutIndex = 10-lastAggregationGroup.length;
-                var partialHierarchy =hierarchyItemArray.slice(0,cutIndex).join().split(",");
-                //add hierarchy to last group and make sure length less than 10
-                lastAggregationGroup = lastAggregationGroup.concat(partialHierarchy);
-                increasedDataGroups[increasedDataGroups.length-1]=lastAggregationGroup;
-                var leftHierarchy = hierarchyItemArray.slice(cutIndex);
-
-                var leftHierarchyLength = leftHierarchy.length;
-                var grpLength = parseInt(leftHierarchyLength/10);
-                if(leftHierarchyLength%10==0&&leftHierarchyLength!=0){
-                    grpLength--;
-                }
-                for(var i=0;i<=grpLength;i++){
-                    var hierAggGroupUnit = leftHierarchy.slice(i*10,(i+1)*10).join().split(",");
-                    increasedDataGroups.push(hierAggGroupUnit);
-                }
+            if (!elemStillExist) {
+              group.splice(j, 1);
+              j--;
             }
           }
-          //lastAggregationGroup length >=10
-          else{
-              var hierrachyArrayLength = hierarchyItemArray.length;
-              var grpLength = parseInt(hierrachyArrayLength/10);
-              if(hierrachyArrayLength%10==0&&hierrachyArrayLength!=0){
-                  grpLength--;
-              }
-              for(var i=0;i<=grpLength;i++){
-                   var hierAggGroupUnit = hierarchyItemArray.slice(i*10,(i+1)*10).join().split(",");
-                   increasedDataGroups.push(hierAggGroupUnit);
-              }
+          if (!group.length) {
+            aggregationGroups.splice(index, 1);
+            index--;
           }
-            //! here get the latest aggregation groups,only effect when add newCube
-            $scope.cubeMetaFrame.rowkey.aggregation_groups = increasedDataGroups;
         }
-    }
-
-    function sortSharedData(oldArray,tmpArr){
-        var newArr = [];
-        for(var j=0;j<oldArray.length;j++){
-            var unit = oldArray[j];
-            for(var k=0;k<tmpArr.length;k++){
-                if(unit.column==tmpArr[k].column){
-                    newArr.push(unit);
-                }
-            }
+        else {
+          aggregationGroups.splice(index, 1);
+          index--;
         }
-        return newArr;
+      });
     }
 
-    function increasedData(oldArray,tmpArr){
-        var increasedData = [];
-        if(oldArray&&!oldArray.length){
-            return   increasedData.concat(tmpArr);
-        }
+    if ($scope.cubeMode === "addNewCube") {
 
-        for(var j=0;j<tmpArr.length;j++){
-            var unit = tmpArr[j];
-            var exist = false;
-            for(var k=0;k<oldArray.length;k++){
-                if(unit==oldArray[k]){
-                    exist = true;
-                    break;
-                }
-            }
-            if(!exist){
-                increasedData.push(unit);
-            }
+      if (!tmpAggregationItems.length) {
+        $scope.cubeMetaFrame.rowkey.aggregation_groups = [];
+        return;
+      }
+
+      var newUniqAggregationItem = [];
+      angular.forEach(tmpAggregationItems, function (item, index) {
+        if (newUniqAggregationItem.indexOf(item) == -1) {
+          newUniqAggregationItem.push(item);
+        }
+      });
+
+      //distinct hierarchyItem
+      var hierarchyItems = hierarchyItemArray.join().split(",");
+      var _hierarchyItems = [];
+      angular.forEach(hierarchyItems, function (item, index) {
+        if (_hierarchyItems.indexOf(item) == -1) {
+          _hierarchyItems.push(item);
+        }
+      });
+      hierarchyItems = _hierarchyItems;
+
+      var unHierarchyItems = increasedData(hierarchyItems, newUniqAggregationItem);
+      //hierarchyItems
+      var increasedDataGroups = sliceGroupItemToGroups(unHierarchyItems);
+      if (!hierarchyItemArray.length) {
+        $scope.cubeMetaFrame.rowkey.aggregation_groups = increasedDataGroups;
+        return;
+      }
+      ;
+
+      var lastAggregationGroup = increasedDataGroups.length === 0 ? [] : increasedDataGroups[increasedDataGroups.length - 1];
+
+      if (lastAggregationGroup.length < 10) {
+        if (lastAggregationGroup.length + hierarchyItemArray.length <= 10) {
+          lastAggregationGroup = lastAggregationGroup.concat(hierarchyItems);
+          if (increasedDataGroups.length == 0) {
+            //case only hierarchy
+            increasedDataGroups[0] = lastAggregationGroup;
+          } else {
+            increasedDataGroups[increasedDataGroups.length - 1] = lastAggregationGroup;
+          }
+        }
+        else {
+          var cutIndex = 10 - lastAggregationGroup.length;
+          var partialHierarchy = hierarchyItemArray.slice(0, cutIndex).join().split(",");
+          //add hierarchy to last group and make sure length less than 10
+          lastAggregationGroup = lastAggregationGroup.concat(partialHierarchy);
+          increasedDataGroups[increasedDataGroups.length - 1] = lastAggregationGroup;
+          var leftHierarchy = hierarchyItemArray.slice(cutIndex);
+
+          var leftHierarchyLength = leftHierarchy.length;
+          var grpLength = parseInt(leftHierarchyLength / 10);
+          if (leftHierarchyLength % 10 == 0 && leftHierarchyLength != 0) {
+            grpLength--;
+          }
+          for (var i = 0; i <= grpLength; i++) {
+            var hierAggGroupUnit = leftHierarchy.slice(i * 10, (i + 1) * 10).join().split(",");
+            increasedDataGroups.push(hierAggGroupUnit);
+          }
+        }
+      }
+      //lastAggregationGroup length >=10
+      else {
+        var hierrachyArrayLength = hierarchyItemArray.length;
+        var grpLength = parseInt(hierrachyArrayLength / 10);
+        if (hierrachyArrayLength % 10 == 0 && hierrachyArrayLength != 0) {
+          grpLength--;
         }
-        return increasedData;
+        for (var i = 0; i <= grpLength; i++) {
+          var hierAggGroupUnit = hierarchyItemArray.slice(i * 10, (i + 1) * 10).join().split(",");
+          increasedDataGroups.push(hierAggGroupUnit);
+        }
+      }
+      //! here get the latest aggregation groups,only effect when add newCube
+      $scope.cubeMetaFrame.rowkey.aggregation_groups = increasedDataGroups;
     }
+  }
 
-    function increasedColumn(oldArray,tmpArr){
-        var increasedData = [];
-        if(oldArray&&!oldArray.length){
-         return   increasedData.concat(tmpArr);
+  function sortSharedData(oldArray, tmpArr) {
+    var newArr = [];
+    for (var j = 0; j < oldArray.length; j++) {
+      var unit = oldArray[j];
+      for (var k = 0; k < tmpArr.length; k++) {
+        if (unit.column == tmpArr[k].column) {
+          newArr.push(unit);
         }
+      }
+    }
+    return newArr;
+  }
 
-        for(var j=0;j<tmpArr.length;j++){
-            var unit = tmpArr[j];
-            var exist = false;
-            for(var k=0;k<oldArray.length;k++){
-                if(unit.column==oldArray[k].column){
-                    exist = true;
-                    break;
-                }
-            }
-            if(!exist){
-                increasedData.push(unit);
-            }
-        }
-        return increasedData;
+  function increasedData(oldArray, tmpArr) {
+    var increasedData = [];
+    if (oldArray && !oldArray.length) {
+      return increasedData.concat(tmpArr);
     }
 
-    function sliceGroupItemToGroups(groupItems){
-        if(!groupItems.length){
-            return [];
+    for (var j = 0; j < tmpArr.length; j++) {
+      var unit = tmpArr[j];
+      var exist = false;
+      for (var k = 0; k < oldArray.length; k++) {
+        if (unit == oldArray[k]) {
+          exist = true;
+          break;
         }
-        var groups = [];
-        var j = -1;
-        for(var i = 0;i<groupItems.length;i++){
-            if(i%10==0){
-                j++;
-                groups[j]=[];
-            }
-            groups[j].push(groupItems[i]);
-        }
-        return groups;
+      }
+      if (!exist) {
+        increasedData.push(unit);
+      }
     }
+    return increasedData;
+  }
 
+  function increasedColumn(oldArray, tmpArr) {
+    var increasedData = [];
+    if (oldArray && !oldArray.length) {
+      return increasedData.concat(tmpArr);
+    }
 
-    // ~ private methods
-    function generateColumnFamily() {
-        $scope.cubeMetaFrame.hbase_mapping.column_family = [];
-        var colFamily = ColFamily();
-        var normalMeasures = [], distinctCountMeasures=[];
-        angular.forEach($scope.cubeMetaFrame.measures, function (measure, index) {
-            if(measure.function.expression === 'COUNT_DISTINCT'){
-                distinctCountMeasures.push(measure);
-            }else{
-                normalMeasures.push(measure);
-            }
-        });
-        if(normalMeasures.length>0){
-            var nmcf = colFamily();
-            angular.forEach(normalMeasures, function(normalM, index){
-                nmcf.columns[0].measure_refs.push(normalM.name);
-            });
-            $scope.cubeMetaFrame.hbase_mapping.column_family.push(nmcf);
+    for (var j = 0; j < tmpArr.length; j++) {
+      var unit = tmpArr[j];
+      var exist = false;
+      for (var k = 0; k < oldArray.length; k++) {
+        if (unit.column == oldArray[k].column) {
+          exist = true;
+          break;
         }
+      }
+      if (!exist) {
+        increasedData.push(unit);
+      }
+    }
+    return increasedData;
+  }
 
-        if (distinctCountMeasures.length > 0){
-            var dccf = colFamily();
-            angular.forEach(distinctCountMeasures, function(dcm, index){
-                dccf.columns[0].measure_refs.push(dcm.name);
-            });
-            $scope.cubeMetaFrame.hbase_mapping.column_family.push(dccf);
-        }
+  function sliceGroupItemToGroups(groupItems) {
+    if (!groupItems.length) {
+      return [];
     }
+    var groups = [];
+    var j = -1;
+    for (var i = 0; i < groupItems.length; i++) {
+      if (i % 10 == 0) {
+        j++;
+        groups[j] = [];
+      }
+      groups[j].push(groupItems[i]);
+    }
+    return groups;
+  }
 
-    $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
-        if(!newValue){
-            return;
-        }
-        var param = {
-            ext: true,
-            project:newValue
-        };
-        if(newValue){
-            TableModel.initTables();
-            TableService.list(param, function (tables) {
-                angular.forEach(tables, function (table) {
-                    table.name = table.database+"."+table.name;
-                    TableModel.addTable(table);
-                });
-            });
-        }
+
+  // ~ private methods
+  function generateColumnFamily() {
+    $scope.cubeMetaFrame.hbase_mapping.column_family = [];
+    var colFamily = ColFamily();
+    var normalMeasures = [], distinctCountMeasures = [];
+    angular.forEach($scope.cubeMetaFrame.measures, function (measure, index) {
+      if (measure.function.expression === 'COUNT_DISTINCT') {
+        distinctCountMeasures.push(measure);
+      } else {
+        normalMeasures.push(measure);
+      }
     });
+    if (normalMeasures.length > 0) {
+      var nmcf = colFamily();
+      angular.forEach(normalMeasures, function (normalM, index) {
+        nmcf.columns[0].measure_refs.push(normalM.name);
+      });
+      $scope.cubeMetaFrame.hbase_mapping.column_family.push(nmcf);
+    }
+
+    if (distinctCountMeasures.length > 0) {
+      var dccf = colFamily();
+      angular.forEach(distinctCountMeasures, function (dcm, index) {
+        dccf.columns[0].measure_refs.push(dcm.name);
+      });
+      $scope.cubeMetaFrame.hbase_mapping.column_family.push(dccf);
+    }
+  }
+
+  $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
+    if (!newValue) {
+      return;
+    }
+    var param = {
+      ext: true,
+      project: newValue
+    };
+    if (newValue) {
+      TableModel.initTables();
+      TableService.list(param, function (tables) {
+        angular.forEach(tables, function (table) {
+          table.name = table.database + "." + table.name;
+          TableModel.addTable(table);
+        });
+      });
+    }
+  });
 
 
   //dimensions options is depend on the model input when add cube
   $scope.$watch('cubeMetaFrame.model_name', function (newValue, oldValue) {
-    if(!newValue){
+    if (!newValue) {
       return;
     }
-    $scope.metaModel.model=modelsManager.getModel(newValue);
+    $scope.metaModel.model = modelsManager.getModel(newValue);
+
+    if(!$scope.metaModel.model){
+      return;
+    }
+    var factTable = $scope.metaModel.model.fact_table;
+    var cols = $scope.getColumnsByTable(factTable);
+    //
+    for(var i=0;i<cols.length;i++){
+      var col = cols[i];
+      if(col.datatype === "timestamp"&&col.name.indexOf("_TS")==-1){
+        $scope.kafkaMeta.parserProperties = "tsColName="+col.name+";formatTs=TRUE";
+        break;
+      }
+    }
+
+  });
+  $scope.$on('DimensionsEdited', function (event) {
+    if ($scope.cubeMetaFrame) {
+      reGenerateRowKey();
+    }
   });
-    $scope.$on('DimensionsEdited', function (event) {
-        if ($scope.cubeMetaFrame) {
-            reGenerateRowKey();
-        }
-    });
 });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/cubeFilter.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeFilter.js b/webapp/app/js/controllers/cubeFilter.js
deleted file mode 100644
index 3953169..0000000
--- a/webapp/app/js/controllers/cubeFilter.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-'use strict';
-
-KylinApp.controller('CubeFilterCtrl', function ($scope, $modal,cubeConfig,MetaModel) {
-
-});

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/cubeMeasures.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeMeasures.js b/webapp/app/js/controllers/cubeMeasures.js
new file mode 100644
index 0000000..cdcd3cf
--- /dev/null
+++ b/webapp/app/js/controllers/cubeMeasures.js
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/license$s/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+'use strict';
+
+KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubesManager,CubeDescModel) {
+
+  $scope.addNewMeasure = function (measure) {
+    $scope.newMeasure = (!!measure)? measure:CubeDescModel.createMeasure();
+  };
+
+  $scope.removeElement = function (arr, element) {
+    var index = arr.indexOf(element);
+    if (index > -1) {
+      arr.splice(index, 1);
+    }
+  };
+
+  $scope.clearNewMeasure = function () {
+    $scope.newMeasure = null;
+  };
+
+  $scope.saveNewMeasure = function () {
+    if ($scope.cubeMetaFrame.measures.indexOf($scope.newMeasure) === -1) {
+      $scope.cubeMetaFrame.measures.push($scope.newMeasure);
+    }
+    $scope.newMeasure = null;
+  };
+
+  //map right return type for param
+  $scope.measureReturnTypeUpdate = function(){
+    if($scope.newMeasure.function.parameter.type=="constant"&&$scope.newMeasure.function.expression!=="COUNT_DISTINCT"){
+      switch($scope.newMeasure.function.expression){
+        case "SUM":
+        case "COUNT":
+          $scope.newMeasure.function.returntype = "bigint";
+          break;
+        default:
+          $scope.newMeasure.function.returntype = "";
+          break;
+      }
+    }
+    if($scope.newMeasure.function.parameter.type=="column"&&$scope.newMeasure.function.expression!=="COUNT_DISTINCT"){
+
+      var column = $scope.newMeasure.function.parameter.value;
+      var colType = $scope.getColumnType(column, $scope.metaModel.model.fact_table); // $scope.getColumnType defined in cubeEdit.js
+
+      if(colType==""||!colType){
+        $scope.newMeasure.function.returntype = "";
+        return;
+      }
+
+
+      switch($scope.newMeasure.function.expression){
+        case "SUM":
+          if(colType==="smallint"||colType==="int"||colType==="bigint"||colType==="integer"){
+            $scope.newMeasure.function.returntype= 'bigint';
+          }else{
+            if(colType.indexOf('decimal')!=-1){
+              $scope.newMeasure.function.returntype= colType;
+            }else{
+              $scope.newMeasure.function.returntype= 'decimal';
+            }
+          }
+          break;
+        case "MIN":
+        case "MAX":
+          $scope.newMeasure.function.returntype = colType;
+          break;
+        case "COUNT":
+          $scope.newMeasure.function.returntype = "bigint";
+          break;
+        default:
+          $scope.newMeasure.function.returntype = "";
+          break;
+      }
+    }
+  }
+
+
+});

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/cubeSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeSchema.js b/webapp/app/js/controllers/cubeSchema.js
index d94316e..b714c41 100755
--- a/webapp/app/js/controllers/cubeSchema.js
+++ b/webapp/app/js/controllers/cubeSchema.js
@@ -18,8 +18,7 @@
 
 'use strict';
 
-KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserService,modelsManager, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,ModelDescService,SweetAlert,cubesManager) {
-
+KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserService,modelsManager, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,ModelDescService,SweetAlert,cubesManager,StreamingService) {
     $scope.modelsManager = modelsManager;
     $scope.cubesManager = cubesManager;
     $scope.projects = [];
@@ -34,6 +33,7 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
     if (UserService.hasRole("ROLE_ADMIN")) {
             $scope.wizardSteps.push({title: 'Advanced Setting', src: 'partials/cubeDesigner/advanced_settings.html', isComplete: false,form:'cube_setting_form'});
     }
+    $scope.wizardSteps.push({title: 'Streaming', src: 'partials/cubeDesigner/streamingConfig.html', isComplete: false,form:'cube_streaming_form'});
     $scope.wizardSteps.push({title: 'Overview', src: 'partials/cubeDesigner/overview.html', isComplete: false,form:null});
 
     $scope.curStep = $scope.wizardSteps[0];
@@ -60,89 +60,6 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
         return $scope.userService.hasRole('ROLE_ADMIN') || $scope.hasPermission(project,$scope.permissions.ADMINISTRATION.mask);
     };
 
-    $scope.addNewMeasure = function (measure) {
-        $scope.newMeasure = (!!measure)? measure:CubeDescModel.createMeasure();
-    };
-
-    $scope.clearNewMeasure = function () {
-        $scope.newMeasure = null;
-    };
-
-    $scope.saveNewMeasure = function () {
-        if ($scope.cubeMetaFrame.measures.indexOf($scope.newMeasure) === -1) {
-            $scope.cubeMetaFrame.measures.push($scope.newMeasure);
-        }
-        $scope.newMeasure = null;
-    };
-
-    //map right return type for param
-    $scope.measureReturnTypeUpdate = function(){
-        if($scope.newMeasure.function.parameter.type=="constant"&&$scope.newMeasure.function.expression!=="COUNT_DISTINCT"){
-            switch($scope.newMeasure.function.expression){
-                case "SUM":
-                case "COUNT":
-                    $scope.newMeasure.function.returntype = "bigint";
-                    break;
-                default:
-                    $scope.newMeasure.function.returntype = "";
-                    break;
-            }
-        }
-        if($scope.newMeasure.function.parameter.type=="column"&&$scope.newMeasure.function.expression!=="COUNT_DISTINCT"){
-
-            var column = $scope.newMeasure.function.parameter.value;
-            var colType = $scope.getColumnType(column, $scope.metaModel.model.fact_table); // $scope.getColumnType defined in cubeEdit.js
-
-            if(colType==""||!colType){
-                $scope.newMeasure.function.returntype = "";
-                return;
-            }
-
-
-            switch($scope.newMeasure.function.expression){
-                case "SUM":
-                    if(colType==="smallint"||colType==="int"||colType==="bigint"||colType==="integer"){
-                        $scope.newMeasure.function.returntype= 'bigint';
-                    }else{
-                        if(colType.indexOf('decimal')!=-1){
-                            $scope.newMeasure.function.returntype= colType;
-                        }else{
-                            $scope.newMeasure.function.returntype= 'decimal';
-                        }
-                    }
-                    break;
-                case "MIN":
-                case "MAX":
-                    $scope.newMeasure.function.returntype = colType;
-                    break;
-                case "COUNT":
-                    $scope.newMeasure.function.returntype = "bigint";
-                    break;
-                default:
-                    $scope.newMeasure.function.returntype = "";
-                    break;
-            }
-        }
-    }
-
-    $scope.addNewRowkeyColumn = function () {
-        $scope.cubeMetaFrame.rowkey.rowkey_columns.push({
-            "column": "",
-            "length": 0,
-            "dictionary": "true",
-            "mandatory": false
-        });
-    };
-
-    $scope.addNewAggregationGroup = function () {
-        $scope.cubeMetaFrame.rowkey.aggregation_groups.push([]);
-    };
-
-    $scope.refreshAggregationGroup = function (list, index, aggregation_groups) {
-        if (aggregation_groups) {
-            list[index] = aggregation_groups;
-        }
-    };
 
     $scope.removeElement = function (arr, element) {
         var index = arr.indexOf(element);
@@ -214,6 +131,16 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
       }
       $scope.metaModel.model=modelsManager.getModel($scope.cubeMetaFrame.model_name);
 
+      StreamingService.getConfig({cubeName:$scope.cubeMetaFrame.name}, function (kfkConfigs) {
+        if(!!kfkConfigs[0]&&kfkConfigs[0].cubeName == $scope.cubeMetaFrame.name){
+          $scope.cubeState.isStreaming = true;
+          $scope.streamingMeta = kfkConfigs[0];
+          StreamingService.getKfkConfig({kafkaConfigName:$scope.streamingMeta.name}, function (streamings) {
+            $scope.kafkaMeta = streamings[0];
+          })
+        }
+      })
+
     }
   });
 
@@ -242,6 +169,9 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
             }else{
                 //business rule check
                 switch($scope.curStep.form){
+                    case 'cube_info_form':
+                      return $scope.check_cube_info();
+                      break;
                     case 'cube_dimension_form':
                         return $scope.check_cube_dimension();
                         break;
@@ -250,6 +180,8 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
                         break;
                     case 'cube_setting_form':
                         return $scope.check_cube_setting();
+                    case 'cube_streaming_form':
+                        return $scope.kafka_ad_config_form();
                     default:
                         return true;
                         break;
@@ -258,6 +190,9 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
         }
     };
 
+  $scope.check_cube_info = function(){
+
+  }
 
     $scope.check_cube_dimension = function(){
         var errors = [];
@@ -327,6 +262,31 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, QueryService, UserServic
         }
     }
 
+  $scope.kafka_ad_config_form = function(){
+    if(!$scope.cubeState.isStreaming){
+      return true;
+    }
+    var errors = [];
+    if(!$scope.kafkaMeta.clusters.length){
+      errors.push("Cluster can't be null");
+    }
+    angular.forEach($scope.kafkaMeta.clusters,function(cluster,index){
+      if(!cluster.brokers.length){
+        errors.push("No broker under Cluster-"+(index+1));
+      }
+    })
+    var errorInfo = "";
+    angular.forEach(errors,function(item){
+      errorInfo+="\n"+item;
+    });
+    if(errors.length){
+      SweetAlert.swal('', errorInfo, 'warning');
+      return false;
+    }else{
+      return true;
+    }
+  }
+
 
     // ~ private methods
     function initProject() {

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/cubes.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubes.js b/webapp/app/js/controllers/cubes.js
index 886aa6b..843ad7a 100644
--- a/webapp/app/js/controllers/cubes.js
+++ b/webapp/app/js/controllers/cubes.js
@@ -19,7 +19,7 @@
 'use strict';
 
 KylinApp
-  .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, cubeConfig, ProjectModel, ModelService, MetaModel, CubeList,modelsManager,cubesManager) {
+  .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, cubeConfig, ProjectModel, ModelService, MetaModel, CubeList,modelsManager,cubesManager,StreamingList) {
 
     $scope.cubeConfig = cubeConfig;
     $scope.cubeList = CubeList;
@@ -62,9 +62,21 @@ KylinApp
       $scope.loading = true;
 
       return CubeList.list(queryParam).then(function (resp) {
-        $scope.loading = false;
-        defer.resolve(resp);
-        return defer.promise;
+
+        StreamingList.list().then(function(_resp){
+          angular.forEach($scope.cubeList.cubes,function(item,index){
+            var result = StreamingList.checkCubeExist(item.name);
+            if(result.exist == true){
+              item.streaming = result.streaming;
+              var kfkConfig = StreamingList.getKafkaConfig(result.streaming.name);
+              item.kfkConfig = kfkConfig;
+            }
+          })
+          $scope.loading = false;
+          defer.resolve(resp);
+          return defer.promise;
+        })
+
       },function(resp){
         $scope.loading = false;
         defer.resolve([]);
@@ -355,7 +367,6 @@ KylinApp
     $scope.cubeEdit = function (cube) {
       $location.path("cubes/edit/" + cube.name);
     }
-
     $scope.startMerge = function (cube) {
       $scope.metaModel={
         model:modelsManager.getModelByCube(cube.name)

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index a2126e8..ccb0013 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -14,235 +14,278 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-*/
+ */
 
 'use strict';
 
-KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log,SweetAlert,modelsManager) {
-
-    $scope.modelsManager = modelsManager;
-
-    $scope.projects = [];
-    $scope.newDimension = null;
-    $scope.newMeasure = null;
-
-    $scope.forms = {};
-
-
-    $scope.wizardSteps = [
-        {title: 'Model Info', src: 'partials/modelDesigner/model_info.html', isComplete: false,form:'model_info_form'},
-        {title: 'Data Model', src: 'partials/modelDesigner/data_model.html', isComplete: false,form:'data_model_form'},
-        {title: 'Dimensions', src: 'partials/modelDesigner/model_dimensions.html', isComplete: false,form:'model_dimensions_form'},
-        {title: 'Measures', src: 'partials/modelDesigner/model_measures.html', isComplete: false,form:'model_measure_form'},
-        {title: 'Settings', src: 'partials/modelDesigner/conditions_settings.html', isComplete: false,form:'model_setting_form'}
-    ];
+KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, $q, AuthenticationService, $filter, ModelService, MetaModel, CubeDescModel, CubeList, TableModel, ProjectModel, $log, SweetAlert, modelsManager) {
+
+  $scope.modelsManager = modelsManager;
+  $scope.projectModel = ProjectModel;
+  $scope.projects = [];
+  $scope.newDimension = null;
+  $scope.newMeasure = null;
+
+  $scope.forms = {};
+
+
+  $scope.wizardSteps = [
+    {title: 'Model Info', src: 'partials/modelDesigner/model_info.html', isComplete: false, form: 'model_info_form'},
+    {title: 'Data Model', src: 'partials/modelDesigner/data_model.html', isComplete: false, form: 'data_model_form'},
+    {
+      title: 'Dimensions',
+      src: 'partials/modelDesigner/model_dimensions.html',
+      isComplete: false,
+      form: 'model_dimensions_form'
+    },
+    {
+      title: 'Measures',
+      src: 'partials/modelDesigner/model_measures.html',
+      isComplete: false,
+      form: 'model_measure_form'
+    },
+    {
+      title: 'Settings',
+      src: 'partials/modelDesigner/conditions_settings.html',
+      isComplete: false,
+      form: 'model_setting_form'
+    }
+  ];
 
-    $scope.curStep = $scope.wizardSteps[0];
+  $scope.curStep = $scope.wizardSteps[0];
 
 
-    // ~ init
-    if (!$scope.state) {
-        $scope.state = {mode: "view"};
+  // ~ init
+  if (!$scope.state) {
+    $scope.state = {mode: "view"};
+  }
+  //init modelsManager
+  if ($scope.state.mode == "edit") {
+    var defer = $q.defer();
+    var queryParam = {};
+    if (!$scope.projectModel.isSelectedProjectValid()) {
+      return;
     }
+    queryParam.projectName = $scope.projectModel.selectedProject;
+    modelsManager.list(queryParam).then(function (resp) {
+      defer.resolve(resp);
+      modelsManager.loading = false;
+      return defer.promise;
+    });
+  }
 
-    $scope.$watch('model', function (newValue, oldValue) {
-        if(!newValue){
-            return;
-        }
-        if ($scope.modelMode=="editExistModel"&&newValue && !newValue.project) {
-            initProject();
-        }
+  $scope.$watch('model', function (newValue, oldValue) {
+    if (!newValue) {
+      return;
+    }
+    if ($scope.modelMode == "editExistModel" && newValue && !newValue.project) {
+      initProject();
+    }
 
-    });
+  });
 
-    // ~ public methods
-    $scope.filterProj = function(project){
-        return $scope.userService.hasRole('ROLE_ADMIN') || $scope.hasPermission(project,$scope.permissions.ADMINISTRATION.mask);
-    };
+  // ~ public methods
+  $scope.filterProj = function (project) {
+    return $scope.userService.hasRole('ROLE_ADMIN') || $scope.hasPermission(project, $scope.permissions.ADMINISTRATION.mask);
+  };
 
-    $scope.removeElement = function (arr, element) {
-        var index = arr.indexOf(element);
-        if (index > -1) {
-            arr.splice(index, 1);
-        }
-    };
+  $scope.removeElement = function (arr, element) {
+    var index = arr.indexOf(element);
+    if (index > -1) {
+      arr.splice(index, 1);
+    }
+  };
 
-    $scope.open = function ($event) {
-        $event.preventDefault();
-        $event.stopPropagation();
+  $scope.open = function ($event) {
+    $event.preventDefault();
+    $event.stopPropagation();
 
-        $scope.opened = true;
-    };
+    $scope.opened = true;
+  };
 
-    $scope.preView = function () {
-        var stepIndex = $scope.wizardSteps.indexOf($scope.curStep);
-        if (stepIndex >= 1) {
-            $scope.curStep.isComplete = false;
-            $scope.curStep = $scope.wizardSteps[stepIndex - 1];
-        }
-    };
+  $scope.preView = function () {
+    var stepIndex = $scope.wizardSteps.indexOf($scope.curStep);
+    if (stepIndex >= 1) {
+      $scope.curStep.isComplete = false;
+      $scope.curStep = $scope.wizardSteps[stepIndex - 1];
+    }
+  };
 
-    $scope.nextView = function () {
-        var stepIndex = $scope.wizardSteps.indexOf($scope.curStep);
+  $scope.nextView = function () {
+    var stepIndex = $scope.wizardSteps.indexOf($scope.curStep);
 
-        if (stepIndex < ($scope.wizardSteps.length - 1)) {
-            $scope.curStep.isComplete = true;
-            $scope.curStep = $scope.wizardSteps[stepIndex + 1];
+    if (stepIndex < ($scope.wizardSteps.length - 1)) {
+      $scope.curStep.isComplete = true;
+      $scope.curStep = $scope.wizardSteps[stepIndex + 1];
 
-            AuthenticationService.ping(function (data) {
-                UserService.setCurUser(data);
-            });
-        }
-    };
+      AuthenticationService.ping(function (data) {
+        UserService.setCurUser(data);
+      });
+    }
+  };
 
-    $scope.checkForm = function(){
-        if(!$scope.curStep.form){
-            return true;
-        }
-        if($scope.state.mode==='view'){
+  $scope.checkForm = function () {
+    if (!$scope.curStep.form) {
+      return true;
+    }
+    if ($scope.state.mode === 'view') {
+      return true;
+    }
+    else {
+      //form validation
+      if ($scope.forms[$scope.curStep.form].$invalid) {
+        $scope.forms[$scope.curStep.form].$sbumitted = true;
+        return false;
+      } else {
+        //business rule check
+        switch ($scope.curStep.form) {
+          case 'data_model_form':
+            return $scope.check_data_model();
+            break;
+          case 'model_info_form':
+            return $scope.check_model_info();
+            break;
+          case 'model_dimensions_form':
+            return $scope.check_model_dimensions();
+            break;
+          case 'model_measure_form':
+            return $scope.check_model_measure();
+            break;
+          case 'model_setting_form':
+            return $scope.check_model_setting();
+            break;
+          default:
             return true;
+            break;
         }
-        else{
-            //form validation
-            if($scope.forms[$scope.curStep.form].$invalid){
-                $scope.forms[$scope.curStep.form].$sbumitted=true;
-                return false;
-            }else{
-                //business rule check
-                switch($scope.curStep.form){
-                    case 'data_model_form':
-                        return $scope.check_data_model();
-                         break;
-                    case 'model_dimensions_form':
-                        return $scope.check_model_dimensions();
-                         break;
-                    case 'model_measure_form':
-                        return $scope.check_model_measure();
-                         break;
-                    case 'model_setting_form':
-                        return $scope.check_model_setting();
-                         break;
-                    default:
-                        return true;
-                        break;
-                }
-            }
-        }
-    };
+      }
+    }
+  };
+
+  $scope.check_model_info = function () {
 
-    /*
-     * lookups can't be null
-     */
-    $scope.check_data_model = function(){
-        var errors = [];
+    var modelName = $scope.modelsManager.selectedModel.name.toUpperCase();
+    var models = $scope.modelsManager.modelNameList;
+    if (models.indexOf(modelName) != -1) {
+      SweetAlert.swal('', "Model named [" + modelName + "] already exist!", 'warning');
+      return false;
+    }
+    return true;
+  }
+
+  /*
+   * lookups can't be null
+   */
+  $scope.check_data_model = function () {
+    var errors = [];
 //        if(!modelsManager.selectedModel.lookups.length){
 //            errors.push("No lookup table defined");
 //        }
-        var errorInfo = "";
-        angular.forEach(errors,function(item){
-            errorInfo+="\n"+item;
-        });
-        if(errors.length){
-            SweetAlert.swal('', errorInfo, 'warning');
-            return false;
-        }else{
-            return true;
-        }
-
+    var errorInfo = "";
+    angular.forEach(errors, function (item) {
+      errorInfo += "\n" + item;
+    });
+    if (errors.length) {
+      SweetAlert.swal('', errorInfo, 'warning');
+      return false;
+    } else {
+      return true;
     }
 
-    /*
-    * dimensions validation
-    * 1.dimension can't be null
-    */
-    $scope.check_model_dimensions = function(){
+  }
 
-        var errors = [];
-        if(!modelsManager.selectedModel.dimensions.length){
-            errors.push("No dimensions defined.");
-        }
-        angular.forEach(modelsManager.selectedModel.dimensions,function(_dimension){
-            if(!_dimension.columns||!_dimension.columns.length){
-            errors.push("No dimension columns defined for Table["+_dimension.table+"]");
-            }
-        });
-        var errorInfo = "";
-        angular.forEach(errors,function(item){
-            errorInfo+="\n"+item;
-        });
-        if(errors.length){
-            SweetAlert.swal('Oops...', errorInfo, 'warning');
-            return false;
-        }else{
-            return true;
-        }
+  /*
+   * dimensions validation
+   * 1.dimension can't be null
+   */
+  $scope.check_model_dimensions = function () {
 
-    };
+    var errors = [];
+    if (!modelsManager.selectedModel.dimensions.length) {
+      errors.push("No dimensions defined.");
+    }
+    angular.forEach(modelsManager.selectedModel.dimensions, function (_dimension) {
+      if (!_dimension.columns || !_dimension.columns.length) {
+        errors.push("No dimension columns defined for Table[" + _dimension.table + "]");
+      }
+    });
+    var errorInfo = "";
+    angular.forEach(errors, function (item) {
+      errorInfo += "\n" + item;
+    });
+    if (errors.length) {
+      SweetAlert.swal('Oops...', errorInfo, 'warning');
+      return false;
+    } else {
+      return true;
+    }
 
-    /*
-     * dimensions validation
-     * 1.metric can't be null
-     */
-    $scope.check_model_measure = function(){
+  };
 
-        var errors = [];
-        if(!modelsManager.selectedModel.metrics||!modelsManager.selectedModel.metrics.length){
-            errors.push("Please define your metrics.");
-        }
-        var errorInfo = "";
-        angular.forEach(errors,function(item){
-            errorInfo+="\n"+item;
-        });
-        if(errors.length){
-            SweetAlert.swal('', errorInfo, 'warning');
-            return false;
-        }else{
-            return true;
-        }
+  /*
+   * dimensions validation
+   * 1.metric can't be null
+   */
+  $scope.check_model_measure = function () {
 
-    };
-    $scope.check_model_setting = function(){
-        var errors = [];
-        if(modelsManager.selectedModel.partition_desc.partition_date_column!=null&& modelsManager.selectedModel.partition_desc.partition_date_start==null){
-            errors.push("Please indicate start date when partition date column selected.");
-        }
-        var errorInfo = "";
-        angular.forEach(errors,function(item){
-            errorInfo+="\n"+item;
-        });
-        if(errors.length){
-            SweetAlert.swal('', errorInfo, 'warning');
-            return false;
-        }else{
-            return true;
-        }
+    var errors = [];
+    if (!modelsManager.selectedModel.metrics || !modelsManager.selectedModel.metrics.length) {
+      errors.push("Please define your metrics.");
+    }
+    var errorInfo = "";
+    angular.forEach(errors, function (item) {
+      errorInfo += "\n" + item;
+    });
+    if (errors.length) {
+      SweetAlert.swal('', errorInfo, 'warning');
+      return false;
+    } else {
+      return true;
     }
 
+  };
+  $scope.check_model_setting = function () {
+    var errors = [];
+    if (modelsManager.selectedModel.partition_desc.partition_date_column != null && modelsManager.selectedModel.partition_desc.partition_date_start == null) {
+      errors.push("Please indicate start date when partition date column selected.");
+    }
+    var errorInfo = "";
+    angular.forEach(errors, function (item) {
+      errorInfo += "\n" + item;
+    });
+    if (errors.length) {
+      SweetAlert.swal('', errorInfo, 'warning');
+      return false;
+    } else {
+      return true;
+    }
+  }
 
-    $scope.goToStep = function(stepIndex){
-        if($scope.state.mode=="edit"){
-            if(stepIndex+1>=$scope.curStep.step){
-                return;
-            }
-        }
-        for(var i=0;i<$scope.wizardSteps.length;i++){
-            if(i<=stepIndex){
-                $scope.wizardSteps[i].isComplete = true;
-            }else{
-                $scope.wizardSteps[i].isComplete = false;
-            }
-        }
-        if (stepIndex < ($scope.wizardSteps.length)) {
-            $scope.curStep = $scope.wizardSteps[stepIndex];
 
-            AuthenticationService.ping(function (data) {
-                UserService.setCurUser(data);
-            });
-        }
+  $scope.goToStep = function (stepIndex) {
+    if ($scope.state.mode == "edit") {
+      if (stepIndex + 1 >= $scope.curStep.step) {
+        return;
+      }
     }
+    for (var i = 0; i < $scope.wizardSteps.length; i++) {
+      if (i <= stepIndex) {
+        $scope.wizardSteps[i].isComplete = true;
+      } else {
+        $scope.wizardSteps[i].isComplete = false;
+      }
+    }
+    if (stepIndex < ($scope.wizardSteps.length)) {
+      $scope.curStep = $scope.wizardSteps[stepIndex];
 
-    // ~ private methods
-    function initProject() {
-
+      AuthenticationService.ping(function (data) {
+        UserService.setCurUser(data);
+      });
     }
+  }
+
+  // ~ private methods
+  function initProject() {
+
+  }
 });

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/sourceMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js
index 9d405dc..1bbe9c8 100755
--- a/webapp/app/js/controllers/sourceMeta.js
+++ b/webapp/app/js/controllers/sourceMeta.js
@@ -19,7 +19,7 @@
 'use strict';
 
 KylinApp
-  .controller('SourceMetaCtrl', function ($scope, $cacheFactory, $q, $window, $routeParams, CubeService, $modal, TableService, $route, loadingRequest, SweetAlert, tableConfig, TableModel) {
+  .controller('SourceMetaCtrl', function ($scope, $cacheFactory, $q, $window, $routeParams, CubeService, $modal, TableService, $route, loadingRequest, SweetAlert, tableConfig, TableModel,cubeConfig) {
     var $httpDefaultCache = $cacheFactory.get('$http');
     $scope.tableModel = TableModel;
     $scope.tableModel.selectedSrcDb = [];
@@ -173,10 +173,11 @@ KylinApp
       });
     };
 
-    var StreamingSourceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig) {
+    var StreamingSourceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig,cubeConfig) {
       $scope.streamingPrefix = "STREAMING_";
       $scope.projectName = projectName;
       $scope.tableConfig = tableConfig;
+      $scope.cubeConfig = cubeConfig;
       $scope.streaming = {
         sourceSchema: '',
         'parseResult': {}
@@ -242,12 +243,9 @@ KylinApp
           columnList = _.sortBy(columnList, function (i) { return i.type; });
         }
 
-          var timeMeasure = ['year_start','month_start','day_start','hour_start','min_start'];
+          var timeMeasure = $scope.cubeConfig.streamingAutoGenerateMeasure;
           for(var i = 0;i<timeMeasure.length;i++){
             var defaultCheck = 'Y';
-            if(timeMeasure[i]=='min_start'){
-              defaultCheck = 'N';
-            }
             columnList.push({
               'name': timeMeasure[i],
               'checked': defaultCheck,

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/streamingConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/streamingConfig.js b/webapp/app/js/controllers/streamingConfig.js
new file mode 100644
index 0000000..53b30e0
--- /dev/null
+++ b/webapp/app/js/controllers/streamingConfig.js
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+KylinApp.controller('streamingConfigCtrl', function ($scope, $q, $routeParams, $location, $window, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, modelConfig, ProjectModel, ModelService, MetaModel, modelsManager, cubesManager, TableModel, $animate,StreamingService,StreamingModel) {
+
+  $scope.addCluster = function () {
+    $scope.kafkaMeta.clusters.push(StreamingModel.createKafkaCluster());
+  };
+
+  $scope.removeCluster = function(cluster){
+
+    SweetAlert.swal({
+      title: '',
+      text: 'Are you sure to remove this cluster ?',
+      type: '',
+      showCancelButton: true,
+      confirmButtonColor: '#DD6B55',
+      confirmButtonText: "Yes",
+      closeOnConfirm: true
+    }, function(isConfirm) {
+      if(isConfirm) {
+        var index = $scope.kafkaMeta.clusters.indexOf(cluster);
+        if (index > -1) {
+          $scope.kafkaMeta.clusters.splice(index, 1);
+        }
+      }
+
+    })
+  }
+
+  $scope.addBroker = function (cluster,broker) {
+    //$scope.modelsManager.selectedModel = model;
+    cluster.newBroker=(!!broker)?broker:StreamingModel.createBrokerConfig();
+  };
+
+  $scope.removeNewBroker = function (cluster){
+    delete cluster.newBroker;
+  }
+
+  $scope.removeElement = function (cluster, element) {
+    var index = cluster.brokers.indexOf(element);
+    if (index > -1) {
+      cluster.brokers.splice(index, 1);
+    }
+  };
+
+  $scope.saveNewBroker = function(cluster){
+    if (cluster.brokers.indexOf(cluster.newBroker) === -1) {
+      cluster.brokers.push(cluster.newBroker);
+    }
+    delete cluster.newBroker;
+  }
+
+  $scope.clearNewBroker = function(cluster){
+    delete cluster.newBroker;
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/controllers/streamingKafkaConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/streamingKafkaConfig.js b/webapp/app/js/controllers/streamingKafkaConfig.js
new file mode 100644
index 0000000..b995aed
--- /dev/null
+++ b/webapp/app/js/controllers/streamingKafkaConfig.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+KylinApp.controller('kafkaConfigCtrl', function ($scope, $q, $routeParams, $location, $window, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, modelConfig, ProjectModel, ModelService, MetaModel, modelsManager, cubesManager, TableModel, $animate,StreamingService) {
+
+});

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/53b383d9/webapp/app/js/model/cubeConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/cubeConfig.js b/webapp/app/js/model/cubeConfig.js
index 93db978..3d80c7f 100644
--- a/webapp/app/js/model/cubeConfig.js
+++ b/webapp/app/js/model/cubeConfig.js
@@ -70,5 +70,6 @@ KylinApp.constant('cubeConfig', {
     {attr: 'last_build_time', name: 'Last Build Time'},
     {attr: 'owner', name: 'Owner'},
     {attr: 'create_time', name: 'Create Time'}
-  ]
+  ],
+  streamingAutoGenerateMeasure:['year_start_ts','month_start_ts','day_start_ts','hour_start_ts','min_start_ts']
 });