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 2016/03/11 03:58:54 UTC

[2/2] kylin git commit: KYLIN-1431 load streaming table ui update add cluster info when add table

KYLIN-1431 load streaming table ui update add cluster info when add table


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

Branch: refs/heads/master
Commit: 890577dad510587400640b40e16810e5caa43df2
Parents: 3569b22
Author: Jason <ji...@163.com>
Authored: Wed Mar 9 19:01:42 2016 +0800
Committer: Jason <ji...@163.com>
Committed: Fri Mar 11 10:58:35 2016 +0800

----------------------------------------------------------------------
 .../kylin/rest/controller/CubeController.java   |  68 -----------
 .../kylin/rest/service/StreamingService.java    |   4 +-
 webapp/app/js/controllers/cubeEdit.js           |  82 ++++++--------
 webapp/app/js/controllers/cubeRefresh.js        |   1 -
 webapp/app/js/controllers/cubeSchema.js         |   2 +-
 webapp/app/js/controllers/sourceMeta.js         |  82 ++++++++++++--
 webapp/app/js/controllers/streamingConfig.js    |   8 ++
 webapp/app/js/model/modelsManager.js            |   1 +
 webapp/app/less/app.less                        |   4 +
 .../partials/cubeDesigner/streamingConfig.html  |  16 +--
 .../app/partials/tables/loadStreamingTable.html |  89 +++++++++++++++
 webapp/app/partials/tables/table_load.html      | 112 +++++--------------
 12 files changed, 242 insertions(+), 227 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/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 e60f330..bc00795 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
@@ -356,74 +356,6 @@ public class CubeController extends BasicController {
             throw new InternalErrorException(e.getLocalizedMessage(), e);
         }
 
-        boolean createStreamingConfigSuccess = false, createKafkaConfigSuccess = false;
-        StreamingConfig streamingConfig = null;
-        KafkaConfig kafkaConfig = null;
-
-        boolean isStreamingCube = cubeRequest.getStreamingCube() != null && cubeRequest.getStreamingCube().equals("true");
-        try {
-            //streaming Cube
-            if (isStreamingCube) {
-                streamingConfig = deserializeStreamingDesc(cubeRequest);
-                kafkaConfig = deserializeKafkaDesc(cubeRequest);
-                // validate before create, rollback when error
-                if (kafkaConfig == null) {
-                    cubeRequest.setMessage("No KafkaConfig info defined.");
-                    return cubeRequest;
-                }
-                if (streamingConfig == null) {
-                    cubeRequest.setMessage("No StreamingConfig info defined.");
-                    return cubeRequest;
-                }
-
-                try {
-                    streamingConfig.setUuid(UUID.randomUUID().toString());
-                    streamingService.createStreamingConfig(streamingConfig);
-                    createStreamingConfigSuccess = true;
-                } catch (IOException e) {
-                    logger.error("Failed to save StreamingConfig:" + e.getLocalizedMessage(), e);
-                    throw new InternalErrorException("Failed to save StreamingConfig: " + e.getLocalizedMessage());
-                }
-                try {
-                    kafkaConfig.setUuid(UUID.randomUUID().toString());
-                    kafkaConfigService.createKafkaConfig(kafkaConfig);
-                    createKafkaConfigSuccess = true;
-                } catch (IOException e) {
-                    logger.error("Failed to save KafkaConfig:" + e.getLocalizedMessage(), e);
-                    throw new InternalErrorException("Failed to save KafkaConfig: " + e.getLocalizedMessage());
-                }
-
-            }
-        } finally {
-            //rollback if failed
-            if (isStreamingCube) {
-                if (createStreamingConfigSuccess == false || createKafkaConfigSuccess == false) {
-                    try {
-                        cubeService.deleteCube(cubeInstance);
-                    } catch (Exception ex) {
-                        throw new InternalErrorException("Failed to rollback on delete cube. " + " Caused by: " + ex.getMessage(), ex);
-                    }
-                    if (createStreamingConfigSuccess == true) {
-                        try {
-                            streamingService.dropStreamingConfig(streamingConfig);
-                        } catch (IOException e) {
-                            throw new InternalErrorException("Failed to create cube, and StreamingConfig created and failed to delete: " + e.getLocalizedMessage());
-                        }
-                    }
-                    if (createKafkaConfigSuccess == true) {
-                        try {
-                            kafkaConfigService.dropKafkaConfig(kafkaConfig);
-                        } catch (IOException e) {
-                            throw new InternalErrorException("Failed to create cube, and KafkaConfig created and failed to delete: " + e.getLocalizedMessage());
-                        }
-                    }
-
-                }
-
-            }
-
-        }
-
         cubeRequest.setUuid(desc.getUuid());
         cubeRequest.setSuccessful(true);
         return cubeRequest;

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/server/src/main/java/org/apache/kylin/rest/service/StreamingService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/StreamingService.java b/server/src/main/java/org/apache/kylin/rest/service/StreamingService.java
index a0473e9..9627e8f 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/StreamingService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/StreamingService.java
@@ -45,7 +45,9 @@ public class StreamingService extends BasicService {
             streamingConfigs = getStreamingManager().listAllStreaming();
         } else {
             StreamingConfig config = getStreamingManager().getConfig(table);
-            streamingConfigs.add(config);
+            if(config!=null){
+                streamingConfigs.add(config);
+            }
         }
 
         return streamingConfigs;

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/controllers/cubeEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js
index 6f0df38..24bdf8d 100755
--- a/webapp/app/js/controllers/cubeEdit.js
+++ b/webapp/app/js/controllers/cubeEdit.js
@@ -171,24 +171,25 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
         if (!modelsManager.getModels().length) {
           ModelDescService.query({model_name: $scope.cubeMetaFrame.model_name}, function (_model) {
             $scope.metaModel.model = _model;
+
+            StreamingService.getConfig({table:$scope.metaModel.model.fact_table}, function (kfkConfigs) {
+              if(!!kfkConfigs[0]){
+                $scope.cubeState.isStreaming = true;
+              }
+              else{
+                return;
+              }
+              $scope.streamingMeta = kfkConfigs[0];
+              StreamingService.getKfkConfig({kafkaConfigName:$scope.streamingMeta.name}, function (streamings) {
+                $scope.kafkaMeta = streamings[0];
+              })
+            })
           });
         }
-        $scope.metaModel.model = modelsManager.getModel($scope.cubeMetaFrame.model_name);
 
         $scope.state.cubeSchema = angular.toJson($scope.cubeMetaFrame, true);
 
-        StreamingService.getConfig({cubeName:$scope.cubeMetaFrame.name}, function (kfkConfigs) {
-          if(!!kfkConfigs[0]){
-            $scope.cubeState.isStreaming = true;
-          }
-          else{
-            return;
-          }
-          $scope.streamingMeta = kfkConfigs[0];
-          StreamingService.getKfkConfig({kafkaConfigName:$scope.streamingMeta.name}, function (streamings) {
-            $scope.kafkaMeta = streamings[0];
-          })
-        })
+
       }
     });
 
@@ -732,41 +733,32 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
   });
 
 
-  $scope.streamingCfg = {
-    parseTsColumn:"{{}}",
-    columnOptions:[]
-  }
   //dimensions options is depend on the model input when add cube
-  $scope.$watch('cubeMetaFrame.model_name', function (newValue, oldValue) {
-    if (!newValue) {
-      return;
-    }
-    $scope.metaModel.model = modelsManager.getModel(newValue);
+  //$scope.$watch('cubeMetaFrame.model_name', function (newValue, oldValue) {
+  //  if (!newValue) {
+  //    return;
+  //  }
+  //  $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"){
+  //      $scope.streamingCfg.columnOptions.push(col.name);
+  //    }
+  //  }
+  //  $scope.kafkaMeta.parserProperties = "tsColName=' ';formatTs=TRUE";
+  //
+  //
+  //});
 
-    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"){
-        $scope.streamingCfg.columnOptions.push(col.name);
-      }
-    }
-    $scope.kafkaMeta.parserProperties = "tsColName=' ';formatTs=TRUE";
 
-
-  });
-
-  $scope.streamingTsColUpdate = function(){
-    if(!$scope.streamingCfg.parseTsColumn){
-      $scope.streamingCfg.parseTsColumn = ' ';
-    }
-    $scope.kafkaMeta.parserProperties = "tsColName="+$scope.streamingCfg.parseTsColumn+";formatTs=TRUE";
-  }
   $scope.$on('DimensionsEdited', function (event) {
     if ($scope.cubeMetaFrame) {
       reGenerateRowKey();

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/controllers/cubeRefresh.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeRefresh.js b/webapp/app/js/controllers/cubeRefresh.js
index d0de50a..ac4b7f7 100644
--- a/webapp/app/js/controllers/cubeRefresh.js
+++ b/webapp/app/js/controllers/cubeRefresh.js
@@ -23,7 +23,6 @@ KylinApp.controller('CubeRefreshCtrl', function ($scope, $modal,cubeConfig,MetaM
 
   //edit model
   if($scope.state.mode==="edit") {
-    $scope.metaModel = MetaModel;
     if(!$scope.cubeMetaFrame.auto_merge_time_ranges){
       $scope.cubeMetaFrame.auto_merge_time_ranges = [];
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/controllers/cubeSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeSchema.js b/webapp/app/js/controllers/cubeSchema.js
index d446730..d4f1e1c 100755
--- a/webapp/app/js/controllers/cubeSchema.js
+++ b/webapp/app/js/controllers/cubeSchema.js
@@ -34,7 +34,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: '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];

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/controllers/sourceMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js
index 69f1a44..472b18b 100755
--- a/webapp/app/js/controllers/sourceMeta.js
+++ b/webapp/app/js/controllers/sourceMeta.js
@@ -422,7 +422,72 @@ KylinApp
       });
     };
 
-    var StreamingSourceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig,cubeConfig) {
+    var StreamingSourceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig,cubeConfig,StreamingModel) {
+
+      $scope.cubeState={
+        "isStreaming": false
+      }
+      $scope.state={
+        'mode':'edit'
+      }
+
+      $scope.streamingMeta = StreamingModel.createStreamingConfig();
+      $scope.kafkaMeta = StreamingModel.createKafkaConfig();
+
+
+      $scope.steps = {
+        curStep:1
+      };
+
+      $scope.streamingCfg = {
+        parseTsColumn:"{{}}",
+        columnOptions:[]
+      }
+
+      $scope.previewStep = function(){
+        $scope.steps.curStep--;
+      }
+
+      $scope.nextStep = function(){
+        //check form
+        $scope.form['setStreamingSchema'].$sbumitted = true;
+        if(!$scope.streaming.sourceSchema||$scope.streaming.sourceSchema===""){
+          return;
+        }
+
+        if(!$scope.table.name||$scope.table.name===""){
+          return;
+        }
+
+        $scope.prepareNextStep();
+
+        if(!$scope.rule.timestampColumnExist){
+          return;
+        }
+
+        $scope.steps.curStep++;
+      }
+
+      $scope.prepareNextStep = function(){
+        $scope.streamingCfg.columnOptions = [];
+        angular.forEach($scope.columnList,function(column,$index){
+          if (column.checked == "Y" && column.fromSource=="Y" && column.type == "timestamp") {
+            $scope.streamingCfg.columnOptions.push(column.name);
+            $scope.rule.timestampColumnExist = true;
+          }
+        })
+
+        if($scope.streamingCfg.columnOptions.length==1){
+          $scope.streamingCfg.parseTsColumn = $scope.streamingCfg.columnOptions[0];
+          $scope.kafkaMeta.parserProperties = "tsColName="+$scope.streamingCfg.parseTsColumn;
+        }
+        if($scope.kafkaMeta.parserProperties!==''){
+          $scope.state.isParserHeaderOpen = false;
+        }else{
+          $scope.state.isParserHeaderOpen = true;
+        }
+      }
+
       $scope.projectName = projectName;
       $scope.tableConfig = tableConfig;
       $scope.cubeConfig = cubeConfig;
@@ -433,7 +498,8 @@ KylinApp
 
       $scope.table = {
         name: '',
-        sourceValid:false
+        sourceValid:false,
+        schemaChecked:false
       }
 
       $scope.cancel = function () {
@@ -447,6 +513,7 @@ KylinApp
       $scope.columnList = [];
 
       $scope.streamingOnChange = function () {
+        $scope.table.schemaChecked = true;
         console.log($scope.streaming.sourceSchema);
         try {
           $scope.streaming.parseResult = JSON.parse($scope.streaming.sourceSchema);
@@ -525,17 +592,9 @@ KylinApp
 
       $scope.form={};
       $scope.rule={
-        'timestampColumnConflict':false
+        'timestampColumnExist':false
       }
       $scope.syncStreamingSchema = function () {
-        $scope.form['setStreamingSchema'].$sbumitted = true;
-        if(!$scope.streaming.sourceSchema||$scope.streaming.sourceSchema===""){
-          return;
-        }
-
-        if(!$scope.table.name||$scope.table.name===""){
-          return;
-        }
 
         var columns = [];
         angular.forEach($scope.columnList,function(column,$index){
@@ -552,6 +611,7 @@ KylinApp
 
         $scope.tableData = {
           "name": $scope.table.name,
+          "source_type":1,
           "columns": columns,
           'database':'Default'
         }

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/controllers/streamingConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/streamingConfig.js b/webapp/app/js/controllers/streamingConfig.js
index 53b30e0..b0a1ebd 100644
--- a/webapp/app/js/controllers/streamingConfig.js
+++ b/webapp/app/js/controllers/streamingConfig.js
@@ -72,4 +72,12 @@ KylinApp.controller('streamingConfigCtrl', function ($scope, $q, $routeParams, $
     delete cluster.newBroker;
   }
 
+
+  $scope.streamingTsColUpdate = function(){
+    if(!$scope.streamingCfg.parseTsColumn){
+      $scope.streamingCfg.parseTsColumn = ' ';
+    }
+    $scope.kafkaMeta.parserProperties = "tsColName="+$scope.streamingCfg.parseTsColumn;
+  }
+
 });

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/js/model/modelsManager.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/modelsManager.js b/webapp/app/js/model/modelsManager.js
index e117053..03f0480 100644
--- a/webapp/app/js/model/modelsManager.js
+++ b/webapp/app/js/model/modelsManager.js
@@ -87,6 +87,7 @@ KylinApp.service('modelsManager',function(ModelService,CubeService,$q,AccessServ
         })
     }
 
+
     this.getModels = function(){
         return _this.models;
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/less/app.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/app.less b/webapp/app/less/app.less
index b6b3131..238e72e 100644
--- a/webapp/app/less/app.less
+++ b/webapp/app/less/app.less
@@ -788,3 +788,7 @@ input:-moz-placeholder {
 .dropdown-menu{
   z-index:9999;
 }
+
+.panel-group .panel{
+  overflow: auto !important;
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/partials/cubeDesigner/streamingConfig.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/streamingConfig.html b/webapp/app/partials/cubeDesigner/streamingConfig.html
index ed03229..c3afd26 100644
--- a/webapp/app/partials/cubeDesigner/streamingConfig.html
+++ b/webapp/app/partials/cubeDesigner/streamingConfig.html
@@ -18,22 +18,8 @@
 
 <div ng-controller="streamingConfigCtrl">
   <ng-form name="forms.cube_streaming_form" novalidate>
-    <div class="form-group">
-      <div class="row">
-        <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default">
-          <b>Is this cube for streaming use?</b>
-        </label>
-        <div class="col-xs-12 col-sm-6" ng-if="state.mode=='edit'" >
-          <toggle-switch ng-model="cubeState.isStreaming" on-label="YES" off-label="NO"> <toggle-switch>
-        </div>
-        <div class="col-xs-12 col-sm-6" ng-if="state.mode=='view'" >
-            <span>{{(!!cubeState.isStreaming)?'YES':'NO'}}</span>
-        </div>
-      </div>
-    </div>
-{{}}
 
-    <div ng-if="cubeState.isStreaming">
+    <div>
       <accordion>
         <accordion-group is-open="state.isKfkSettingOpen" ng-init="state.isKfkSettingOpen=true">
           <accordion-heading>

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/partials/tables/loadStreamingTable.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/loadStreamingTable.html b/webapp/app/partials/tables/loadStreamingTable.html
new file mode 100644
index 0000000..5e6116c
--- /dev/null
+++ b/webapp/app/partials/tables/loadStreamingTable.html
@@ -0,0 +1,89 @@
+
+<div class="modal-body streaming-source" style="height: 360px;">
+  <div class="col-xs-5">
+    <p class="text-info">
+      Need to input streaming source record here, will detect the source schema and create a table schema for
+      streaming.
+    </p>
+    <div class="has-error" ng-if="!table.sourceValid&&table.schemaChecked">
+      <small class="help-block">
+        Source json invalid.
+      </small>
+    </div>
+    <div style="padding:15px;" class="has-error">
+      <small class="help-block" ng-show="streaming.sourceSchema==''&&form.setStreamingSchema.$sbumitted">Please
+        input Streaming source record to generate schema.
+      </small>
+    </div>
+    <div style="margin-bottom: 20px;">
+      <span class="label label-info">JSON</span>
+    </div>
+    <div ng-model="streaming.sourceSchema" ui-ace="{
+    useWrapMode : true,
+    mode:'json',
+    onLoad: streamingOnLoad
+  }">
+
+    </div>
+  </div>
+  <div class="col-xs-1" style="margin-top:300px;text-align:center;">
+    <button type="button" class="btn btn-primary" ng-click="streamingOnChange()"><i
+      class="fa fa-angle-double-right fa-5" style="font-size:2em;"></i></button>
+  </div>
+  <div class="col-xs-6" ng-show="table.schemaChecked">
+    <ol class="text-info" style="margin-bottom: 30px;">
+      <li>Choose 'timestamp' type column for streaming table.</li>
+      <li>derived time dimensions are calculated from timestamp field to help analysis against different time granularities.</li>
+    </ol>
+    <form class="form-horizontal" name="form.setStreamingSchema" novalidate>
+      <div class="form-group required">
+        <label class="col-xs-4 control-label" style="text-align: left;">Table Name</label>
+
+        <div class="col-xs-8"
+             ng-class="{'has-error':form.setStreamingSchema.streamingObject.$invalid && (form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)}">
+          <input type="text" name="streamingObject" required="" ng-model="table.name" class="form-control"/>
+          <small class="help-block"
+                 ng-show="form.setStreamingSchema.streamingObject.$error.required&&(form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)">
+            Table name is required.
+          </small>
+        </div>
+      </div>
+    </form>
+    <table class="table table-hover table-bordered">
+      <tr>
+        <th></th>
+        <th>Column</th>
+        <th>Column Type</th>
+        <th>Comment</th>
+      </tr>
+      <tr ng-repeat="column in columnList">
+        <td><label style="width:100%;cursor: pointer;" for="{{column.name}}"><input style="width:1em;height:1em;"
+                                                                                    type="checkbox"
+                                                                                    id="{{column.name}}"
+                                                                                    ng-model="column.checked"
+                                                                                    ng-true-value="Y"
+                                                                                    ng-false-value="N"/></label>
+        </td>
+        <td>{{column.name}}</td>
+        <td>
+          <select chosen ng-model="column.type"
+                  ng-options="type as type for type in tableConfig.dataTypes"
+                  data-placeholder="select a column type"
+                  style="width: 120px !important;"
+                  class="chosen-select">
+          </select>
+        </td>
+        <td>
+          <label ng-if="column.type=='timestamp'&&column.fromSource=='Y'" class="badge badge-info">timestamp</label>
+          <label ng-if="column.fromSource=='N'" class="badge badge-info">derived time dimension</label>
+        </td>
+      </tr>
+    </table>
+
+    <div class="has-error" ng-if="!rule.timestampColumnExist&&form.setStreamingSchema.$sbumitted">
+      <small class="help-block">
+        You should choose at least one 'timestamp' type column generated from source schema.
+      </small>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/890577da/webapp/app/partials/tables/table_load.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/table_load.html b/webapp/app/partials/tables/table_load.html
index 29a2e9a..1fd4751 100644
--- a/webapp/app/partials/tables/table_load.html
+++ b/webapp/app/partials/tables/table_load.html
@@ -33,98 +33,40 @@
   </script>
 
   <script type="text/ng-template" id="addStreamingSource.html">
-    <div class="modal-header">
-      <h2>Create Streaming Table Schema</h2>
-    </div>
 
-    <div class="modal-body streaming-source" style="height: 660px;">
-      <div class="col-xs-5">
-        <p class="text-info">
-          Need to input streaming source record here, will detect the source schema and create a table schema for
-          streaming.
-        </p>
-
-        <div style="padding:15px;" class="has-error">
-          <small class="help-block" ng-show="streaming.sourceSchema==''&&form.setStreamingSchema.$sbumitted">Please
-            input Streaming source record to generate schema.
-          </small>
-        </div>
-        <div style="margin-bottom: 20px;">
-          <span class="label label-info">JSON</span>
-        </div>
-        <div ng-model="streaming.sourceSchema" ui-ace="{
-    useWrapMode : true,
-    mode:'json',
-    onLoad: streamingOnLoad
-  }">
+    <div class="modal-header">
+      <div class="box-header">
+        <h3 class="box-title">Streaming Table And Cluster Info</h3>
 
+        <div class="box-tools pull-right">
+          <button type="button" class="btn btn-box-tool" ng-click="cancel()" data-widget="remove"><i class="fa fa-times"></i></button>
         </div>
       </div>
-      <div class="col-xs-1" style="margin-top:300px;text-align:center;">
-        <button type="button" class="btn btn-primary" ng-click="streamingOnChange()"><i
-          class="fa fa-angle-double-right fa-5" style="font-size:2em;"></i></button>
-      </div>
-      <div class="col-xs-6" ng-show="table.sourceValid">
-        <ol class="text-info" style="margin-bottom: 30px;">
-          <li>Choose 'timestamp' type column for streaming table.</li>
-          <li>derived time dimensions are calculated from timestamp field to help analysis against different time granularities.</li>
-        </ol>
-        <form class="form-horizontal" name="form.setStreamingSchema" novalidate>
-          <div class="form-group required">
-            <label class="col-xs-4 control-label" style="text-align: left;">Table Name</label>
+    </div>
 
-            <div class="col-xs-8"
-                 ng-class="{'has-error':form.setStreamingSchema.streamingObject.$invalid && (form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)}">
-              <input type="text" name="streamingObject" required="" ng-model="table.name" class="form-control"/>
-              <small class="help-block"
-                     ng-show="form.setStreamingSchema.streamingObject.$error.required&&(form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)">
-                Table name is required.
-              </small>
-            </div>
+    <div class="modal-body streaming-source" style="height: 660px;overflow-y:auto;">
+        <div ng-show="steps.curStep==1" ng-include="'partials/tables/loadStreamingTable.html'"></div>
+        <div ng-show="steps.curStep==2" ng-include="'partials/cubeDesigner/streamingConfig.html'"></div>
+    </div>
+    <div class="modal-footer">
+      <div class="row">
+        <div class="col-xs-8">
+          <div>
           </div>
-        </form>
-        <table class="table table-hover table-bordered">
-          <tr>
-            <th></th>
-            <th>Column</th>
-            <th>Column Type</th>
-            <th>Comment</th>
-          </tr>
-          <tr ng-repeat="column in columnList">
-            <td><label style="width:100%;cursor: pointer;" for="{{column.name}}"><input style="width:1em;height:1em;"
-                                                                                        type="checkbox"
-                                                                                        id="{{column.name}}"
-                                                                                        ng-model="column.checked"
-                                                                                        ng-true-value="Y"
-                                                                                        ng-false-value="N"/></label>
-            </td>
-            <td>{{column.name}}</td>
-            <td>
-              <select chosen ng-model="column.type"
-                      ng-options="type as type for type in tableConfig.dataTypes"
-                      data-placeholder="select a column type"
-                      style="width: 120px !important;"
-                      class="chosen-select">
-              </select>
-            </td>
-            <td>
-              <label ng-if="column.type=='timestamp'&&column.fromSource=='Y'" class="badge badge-info">timestamp</label>
-              <label ng-if="column.fromSource=='N'" class="badge badge-info">derived time dimension</label>
-            </td>
-          </tr>
-        </table>
-
-        <div class="has-error" ng-if="rule.timestampColumnConflict">
-          <small class="help-block">
-            You should choose one, and only one 'timestamp' type column generated from source schema.
-          </small>
+        </div>
+        <div class="col-xs-4">
+          <button class="btn btn-prev" ng-click="previewStep();" ng-show="steps.curStep==2">
+            <i class="ace-icon fa fa-arrow-left"></i>
+            Prev
+          </button>
+          <button id="nextButton" class="btn btn-success btn-next"  ng-click="nextStep();" ng-show="steps.curStep==1">
+            Next
+            <i class="ace-icon fa fa-arrow-right icon-on-right"></i>
+          </button>
+          <button class="btn btn-primary" ng-click="syncStreamingSchema()" ng-show="steps.curStep==2">
+            Submit
+          </button>
         </div>
       </div>
     </div>
-    <div class="modal-footer">
-      <button class="btn btn-primary" ng-click="syncStreamingSchema()" ng-disabled="form.setStreamingSchema.$invalid">
-        Submit
-      </button>
-      <button class="btn btn-primary" ng-click="cancel()">Cancel</button>
-    </div>
   </script>