KYLIN-1786 UI for extended columns as measure
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/469aa400 Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/469aa400 Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/469aa400 Branch: refs/heads/1.5.x-CDH5.7 Commit: 469aa40030c930e64c7a6af5f6d011e3080dfa84 Parents: 6747b2a Author: Jason <jiat...@163.com> Authored: Tue Jul 12 20:38:46 2016 +0800 Committer: Jason <jiat...@163.com> Committed: Tue Jul 12 20:38:46 2016 +0800 ---------------------------------------------------------------------- webapp/app/js/controllers/cubeEdit.js | 52 ++++++++ webapp/app/js/controllers/cubeMeasures.js | 60 +++++---- webapp/app/js/directives/directives.js | 43 +++++++ webapp/app/js/model/cubeConfig.js | 2 +- webapp/app/partials/cubeDesigner/measures.html | 132 +++++++++++++++----- 5 files changed, 237 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/469aa400/webapp/app/js/controllers/cubeEdit.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js index b6fc875..8475025 100755 --- a/webapp/app/js/controllers/cubeEdit.js +++ b/webapp/app/js/controllers/cubeEdit.js @@ -119,6 +119,58 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio }; + $scope.getExtendedColumns = function (measure) { + //metric from model + var me_columns = []; + if($scope.metaModel.model.metrics){ + angular.forEach($scope.metaModel.model.metrics,function(metric,index){ + me_columns.push(metric); + }) + } + angular.forEach($scope.metaModel.model.dimensions,function(dimension,index){ + if(dimension.columns){ + me_columns = me_columns.concat(dimension.columns); + } + }) + + return me_columns; + + }; + + $scope.getExtendedFactColumns = function (measure) { + var me_columns = []; + angular.forEach($scope.metaModel.model.dimensions,function(dimension,index){ + if($scope.metaModel.model.fact_table !== dimension.table){ + return; + } + + if(dimension.columns){ + me_columns = me_columns.concat(dimension.columns); + } + }) + + return me_columns; + + }; + + + $scope.getFactColumns = function () { + var me_columns = []; + angular.forEach($scope.cubeMetaFrame.dimensions,function(dimension,index){ + if($scope.metaModel.model.fact_table !== dimension.table){ + return; + } + if(dimension.column && dimension.derived == null){ + me_columns.push(dimension.column); + } + + }); + + return me_columns; + + }; + + $scope.getColumnType = function (_column, table) { var columns = $scope.getColumnsByTable(table); http://git-wip-us.apache.org/repos/asf/kylin/blob/469aa400/webapp/app/js/controllers/cubeMeasures.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/cubeMeasures.js b/webapp/app/js/controllers/cubeMeasures.js index fb9d292..bb22a42 100644 --- a/webapp/app/js/controllers/cubeMeasures.js +++ b/webapp/app/js/controllers/cubeMeasures.js @@ -24,27 +24,30 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes $scope.addNewMeasure = function (measure) { $scope.nextParameters = []; $scope.newMeasure = (!!measure)? measure:CubeDescModel.createMeasure(); - if(!!measure){ - $scope.convertNextParameters(); + //if(!!measure){ + // $scope.convertNextParameters(); + //} + if(!!measure && measure.function.parameter.next_parameter){ + $scope.nextPara.value = measure.function.parameter.next_parameter.value; } }; - $scope.convertNextParameters = function(){ - $scope.nextParameters = []; - var paramater = jQuery.extend(true, {}, $scope.newMeasure.function.parameter); - while(paramater.next_parameter){ - var paraMeter = - { - "type": paramater.next_parameter.type, - "value":paramater.next_parameter.value, - "next_parameter":null - } - $scope.nextParameters.push(paraMeter); - - paramater = paramater.next_parameter; - - } - - } + //$scope.convertNextParameters = function(){ + // $scope.nextParameters = []; + // var paramater = jQuery.extend(true, {}, $scope.newMeasure.function.parameter); + // while(paramater.next_parameter){ + // var paraMeter = + // { + // "type": paramater.next_parameter.type, + // "value":paramater.next_parameter.value, + // "next_parameter":null + // } + // $scope.nextParameters.push(paraMeter); + // + // paramater = paramater.next_parameter; + // + // } + // + //} $scope.updateNextParameter = function(){ //jQuery.extend(true, {},$scope.newMeasure.function.parameter.next_parameter) @@ -70,6 +73,14 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes } $scope.updateNextParameter(); } + + + $scope.nextPara = { + "type":"column", + "value":"", + "next_parameter":null + } + $scope.openParameterModal = function (parameter) { $modal.open({ templateUrl: 'nextParameter.html', @@ -95,13 +106,19 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes $scope.clearNewMeasure = function () { $scope.newMeasure = null; + $scope.nextPara.value = ""; }; $scope.saveNewMeasure = function () { - if ($scope.newMeasure.function.expression === 'TOP_N' && $scope.nextParameters.length == 0) { + + if ($scope.newMeasure.function.expression === 'TOP_N' && $scope.nextPara.value == "") { SweetAlert.swal('', '[TOP_N] Group by Column is required', 'warning'); return false; } + if($scope.nextPara.value!=="" && ($scope.newMeasure.function.expression == 'EXTENDED_COLUMN' || $scope.newMeasure.function.expression == 'TOP_N')){ + $scope.newMeasure.function.parameter.next_parameter = $scope.nextPara; + } + if ($scope.cubeMetaFrame.measures.indexOf($scope.newMeasure) === -1) { $scope.cubeMetaFrame.measures.push($scope.newMeasure); } @@ -112,7 +129,8 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes //map right return type for param $scope.measureReturnTypeUpdate = function(){ - if($scope.newMeasure.function.expression == 'TOP_N'){ + if($scope.newMeasure.function.expression == 'TOP_N'||$scope.newMeasure.function.expression == 'EXTENDED_COLUMN'){ + $scope.newMeasure.function.parameter.type= 'column'; return; } http://git-wip-us.apache.org/repos/asf/kylin/blob/469aa400/webapp/app/js/directives/directives.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/directives/directives.js b/webapp/app/js/directives/directives.js index ae90c82..4b83865 100644 --- a/webapp/app/js/directives/directives.js +++ b/webapp/app/js/directives/directives.js @@ -332,6 +332,29 @@ KylinApp.directive('kylinPagination', function ($parse, $q) { }; } }; +}).directive("extendedcolumntree", function($compile) { + return { + restrict: "E", + transclude: true, + scope: { + nextpara: '=' + }, + template: + '<li class="parent_li">Host Column:<b>{{nextpara.value}}</b></b></li>' + + '<li class="parent_li">Extended Column:<b>{{nextpara.next_parameter.value}}</b></li>', + compile: function(tElement, tAttr, transclude) { + var contents = tElement.contents().remove(); + var compiledContents; + return function(scope, iElement, iAttr) { + if(!compiledContents) { + compiledContents = $compile(contents, transclude); + } + compiledContents(scope, function(clone, scope) { + iElement.append(clone); + }); + }; + } + }; }).directive('kylinpopover', function ($compile,$templateCache) { return { restrict: "A", @@ -355,4 +378,24 @@ KylinApp.directive('kylinPagination', function ($parse, $q) { $(element).popover(options); } }; +}).directive('extendedColumnReturn', function() { + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModelController) { + + var prefix = "extendedcolumn("; + var suffix = ")"; + ngModelController.$parsers.push(function(data) { + //convert data from view format to model format + return prefix +data+suffix; //converted + }); + + ngModelController.$formatters.push(function(data) { + //convert data from model format to view format + var prefixIndex = data.indexOf("(")+1; + var suffixIndex = data.indexOf(")"); + return data.substring(prefixIndex,suffixIndex); //converted + }); + } + } }); http://git-wip-us.apache.org/repos/asf/kylin/blob/469aa400/webapp/app/js/model/cubeConfig.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/model/cubeConfig.js b/webapp/app/js/model/cubeConfig.js index 82dfca4..88e2133 100644 --- a/webapp/app/js/model/cubeConfig.js +++ b/webapp/app/js/model/cubeConfig.js @@ -20,7 +20,7 @@ KylinApp.constant('cubeConfig', { //~ Define metadata & class measureParamType: ['column', 'constant'], - measureExpressions: ['SUM', 'MIN', 'MAX', 'COUNT', 'COUNT_DISTINCT',"TOP_N", 'RAW'], + measureExpressions: ['SUM', 'MIN', 'MAX', 'COUNT', 'COUNT_DISTINCT',"TOP_N", 'RAW','EXTENDED_COLUMN'], dimensionDataTypes: ["string", "tinyint", "int", "bigint", "date"], cubePartitionTypes: ['APPEND'], joinTypes: [ http://git-wip-us.apache.org/repos/asf/kylin/blob/469aa400/webapp/app/partials/cubeDesigner/measures.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/cubeDesigner/measures.html b/webapp/app/partials/cubeDesigner/measures.html index 5778003..0a39210 100755 --- a/webapp/app/partials/cubeDesigner/measures.html +++ b/webapp/app/partials/cubeDesigner/measures.html @@ -43,8 +43,9 @@ <td> <div class="paraTree"> <ul> - <parametertree ng-if="measure.function.parameter!=null && measure.function.expression!=='TOP_N'" nextpara="measure.function.parameter"></parametertree> + <parametertree ng-if="measure.function.parameter!=null && measure.function.expression!=='TOP_N' && measure.function.expression!=='EXTENDED_COLUMN'" nextpara="measure.function.parameter"></parametertree> <topntree ng-if="measure.function.parameter!=null && measure.function.expression=='TOP_N'" nextpara="measure.function.parameter"></topntree> + <extendedcolumntree ng-if="measure.function.parameter!=null && measure.function.expression=='EXTENDED_COLUMN'" nextpara="measure.function.parameter"></extendedcolumntree> </ul> </div> <!--<span ng-if="measure.function.parameter.next_parameter!=null">{{measure.function.parameter.next_parameter |json}}</span>--> @@ -111,7 +112,7 @@ </div> </div> <!--Param Type--> - <div class="form-group"> + <div class="form-group" ng-if="newMeasure.function.expression !== 'EXTENDED_COLUMN' && newMeasure.function.expression !== 'TOP_N'"> <div class="row"> <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"><b>Param Type</b></label> <div class="col-xs-12 col-sm-6"> @@ -133,9 +134,11 @@ <div class="form-group middle-popover"> <div class="row"> <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"> - <b>Param Value</b> <i class="fa fa-info-circle" kylinpopover placement="right" title="Param Value" template="paramvalueTip.html"></i> + <b ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'">Host column On Fact Table</b> <i ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'" title="Host Column" class="fa fa-info-circle" kylinpopover placement="right" template="hostTableTip.html"></i> + <b ng-if="newMeasure.function.expression == 'TOP_N'">ORDER|SUM by Column</b> <i ng-if="newMeasure.function.expression == 'TOP_N'" class="fa fa-info-circle" title="ORDER|SUM by Column" kylinpopover placement="right" template="topnTip.html"></i> + <b ng-if="newMeasure.function.expression !== 'EXTENDED_COLUMN' && newMeasure.function.expression !== 'TOP_N' ">Param Value</b> <i ng-if="newMeasure.function.expression !== 'EXTENDED_COLUMN' && newMeasure.function.expression !== 'TOP_N' " class="fa fa-info-circle" kylinpopover placement="right" title="Param Value" template="paramvalueTip.html"></i> <!--tip for top_n--> - <small ng-if="newMeasure.function.expression == 'TOP_N'" class="help-block" style="color:#3a87ad">(SUM|ORDER BY Column for TOP_N)</small> + <!--<small ng-if="newMeasure.function.expression == 'TOP_N'" class="help-block" style="color:#3a87ad">(SUM|ORDER BY Column for TOP_N)</small>--> </label> @@ -146,19 +149,29 @@ ng-init="newMeasure.function.parameter.value = 1"><b> 1</b></span> <!--!COUNT_DISTINCT--> <select class="form-control" chosen - ng-if="newMeasure.function.parameter.type == 'column'" + ng-if="newMeasure.function.parameter.type == 'column' && newMeasure.function.expression !== 'EXTENDED_COLUMN'" ng-model="newMeasure.function.parameter.value" ng-change="measureReturnTypeUpdate();" ng-options="column as column for column in getCommonMetricColumns(newMeasure)" > <option value="">-- Select a Column --</option> </select> + <select class="form-control" chosen + ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'" + ng-model="newMeasure.function.parameter.value" + ng-change="measureReturnTypeUpdate();" + ng-options="column as column for column in getFactColumns()" > + <option value="">-- Select a Column --</option> + </select> </div> </div> </div> <!--Return Type--> - <div class="form-group"> + <div class="form-group middle-popover"> <div class="row"> - <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"><b>Return Type</b></label> + <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"> + <b ng-if="newMeasure.function.expression !== 'EXTENDED_COLUMN'">Return Type</b> + <b ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'">Maximum length of extended column</b> <i ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'" title="Maximum Length" class="fa fa-info-circle" kylinpopover placement="right" template="extendedTypeTip.html"></i> + </label> <div class="col-xs-12 col-sm-6"> <select class="form-control" ng-if="newMeasure.function.expression == 'COUNT_DISTINCT'" @@ -174,13 +187,53 @@ ng-options="ddt.value as ddt.name for ddt in cubeConfig.topNTypes"> <option value=""></option> </select> + + <input extended-column-return + ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'" + type="text" placeholder="Kylin wonât save more than this number of bytes" class="form-control" + tooltip-trigger="focus" + ng-init="newMeasure.function.returntype=newMeasure.function.returntype?newMeasure.function.returntype:'extendedcolumn(100)'" + ng-model="newMeasure.function.returntype" required /> + <span class="font-color-default" - ng-if="newMeasure.function.expression != 'COUNT_DISTINCT' && newMeasure.function.expression != 'TOP_N'" + ng-if="newMeasure.function.expression != 'COUNT_DISTINCT' && newMeasure.function.expression != 'TOP_N' && newMeasure.function.expression != 'EXTENDED_COLUMN' " ><b> {{newMeasure.function.returntype | uppercase}}</b> </span> </div> </div> </div> + + + <div class="form-group middle-popover" ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'"> + <div class="row"> + <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"> + <b>Extended column on fact table</b> <i ng-if="newMeasure.function.expression == 'EXTENDED_COLUMN'" title="Extended Column" class="fa fa-info-circle" kylinpopover placement="right" template="extendedColumnTip.html"></i> + </label> + <div class="col-xs-12 col-sm-6"> + <select class="form-control" chosen ng-if="nextPara.type !== 'constant'" required + ng-model="nextPara.value" + ng-options="column as column for column in getExtendedFactColumns()" > + <option value=""></option> + </select> + </div> + </div> + </div> + + <div class="form-group" ng-if="newMeasure.function.expression == 'TOP_N'"> + <div class="row"> + <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"> + <b>Group by Column</b> + </label> + <div class="col-xs-12 col-sm-6"> + <select class="form-control" chosen ng-if="nextPara.type !== 'constant'" required + ng-model="nextPara.value" + ng-options="column as column for column in getExtendedColumns(newMeasure)" > + <option value=""></option> + </select> + </div> + </div> + </div> + <!--Name--> <div class="form-group"> <div class="row"> @@ -207,26 +260,14 @@ </tr> </table> - <table class="table table-hover table-bordered list" ng-if="nextParameters.length" ng-show="newMeasure.function.expression == 'TOP_N'"> - <tr ng-repeat="n_parameter in nextParameters track by $index"> - <td><b>Group By Column</b></td> - <td>{{n_parameter.value}}</td> - <td> - <button class="btn btn-xs btn-info" ng-click="editNextParameter(n_parameter)"> - <i class="fa fa-pencil"></i> - </button> - <button class="btn btn-xs btn-info" ng-click="removeParameter(nextParameters, $index)"><i class="fa fa-minus"></i> - </button> - - </td> - - </tr> - </table> - <button class="btn btn-sm btn-info" ng-click="addNextParameter()" ng-show="newMeasure.function.expression == 'TOP_N' && nextParameters.length==0" - ng-show="state.mode=='edit'"><i class="fa fa-plus"> Group by Column</i> - </button> + <!--<button class="btn btn-sm btn-info" ng-click="addNextParameter()" ng-show="newMeasure.function.expression == 'TOP_N' && nextParameters.length==0"--> + <!--ng-show="state.mode=='edit'"><i class="fa fa-plus"> Group by Column</i>--> + <!--</button>--> + <!--<button class="btn btn-sm btn-info" ng-click="addNextParameter()" ng-show="newMeasure.function.expression == 'EXTENDED_COLUMN' && nextParameters.length==0"--> + <!--ng-show="state.mode=='edit'"><i class="fa fa-plus"> Extended Column On Fact Table</i>--> + <!--</button>--> </div> </div> </div> @@ -248,7 +289,7 @@ <script type="text/ng-template" id="nextParameter.html"> <div class="modal-header"> - <h4 tooltip="submit" ng-if="newmea.measure&&newmea.measure.function.expression !== 'TOP_N'">Add Parameter</h4> + <h4 tooltip="submit" ng-if="newmea.measure&&newmea.measure.function.expression == 'EXTENDED_COLUMN'">Add Extended Column</h4> <h4 tooltip="submit" ng-if="newmea.measure&&newmea.measure.function.expression == 'TOP_N'">Select Group By Column</h4> </div> <div class="modal-body" style="background-color: white"> @@ -258,7 +299,7 @@ <div class="col-md-8"> <div class="row"> <div class="form-group"> - <div class="row" ng-if="newmea.measure&&newmea.measure.function.expression !== 'TOP_N'"> + <div class="row" ng-if="newmea.measure&&newmea.measure.function.expression !== 'TOP_N' && newmea.measure.function.expression !== 'EXTENDED_COLUMN'"> <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"><b>Param Type</b></label> <div class="col-xs-12 col-sm-6"> <select class="form-control" @@ -280,7 +321,7 @@ <div class="row"> <div class="form-group"> - <div ng-if="newmea.measure&&newmea.measure.function.expression !== 'TOP_N'" class="row"> + <div ng-if="newmea.measure&&newmea.measure.function.expression !== 'TOP_N' && newmea.measure.function.expression !== 'EXTENDED_COLUMN" class="row"> <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default"><b>Param Value</b></label> <!--COUNT_DISTINCT--> <div class="col-xs-12 col-sm-6"> @@ -301,12 +342,23 @@ <div class="col-xs-12 col-sm-6"> <select class="form-control" chosen ng-model="nextPara.value" - ng-options="column as column for column in getCommonMetricColumns(newmea.measure)" > + ng-options="column as column for column in getExtendedColumns(newmea.measure)" > <option value=""></option> </select> </div> </div> + <div ng-if="newmea.measure&&newmea.measure.function.expression == 'EXTENDED_COLUMN'" ng-init="nextPara.type='column'" class="row"> + <label class="col-xs-12 col-sm-4 control-label no-padding-right font-color-default"><b>Extended Column On Fact Table</b></label> + <!--COUNT_DISTINCT--> + <div class="col-xs-12 col-sm-6"> + <select class="form-control" chosen + ng-model="nextPara.value" + ng-options="column as column for column in getExtendedColumns(newmea.measure)" > + <option value=""></option> + </select> + </div> + </div> </div> </div> @@ -329,3 +381,23 @@ <li>Distinct Count is approximate, please indicate Error Rate, higher accuracy degree accompanied with larger storage size and longer build time</li> </ol> </script> + +<script type="text/ng-template" id="extendedTypeTip.html"> + <p> + Kylin wonât save more than this number of bytes for each extended column. If exceeded it will be truncated. + </p> +</script> + +<script type="text/ng-template" id="topnTip.html"> + <p>Will use this column for SUM and Order by</p> +</script> + +<script type="text/ng-template" id="hostTableTip.html"> + <p>Host column is the dimension to derive from, e.g. page_id</p> +</script> +<script type="text/ng-template" id="extendedColumnTip.html"> + <p> + Extended column is derived from host, e.g. page_url. No filters on extended column! + </p> +</script> +