KYLIN-1767-WEB-UI-FOR-TOPN Signed-off-by: shaofengshi <shaofeng...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/9e2970bc Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/9e2970bc Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/9e2970bc Branch: refs/heads/1.5.x-CDH5.7 Commit: 9e2970bc4a87d3848ba6677fd2d05c9ed86e15d9 Parents: 111e984 Author: zx chen <346839...@qq.com> Authored: Thu Sep 1 15:16:30 2016 +0800 Committer: shaofengshi <shaofeng...@apache.org> Committed: Fri Sep 2 19:42:22 2016 +0800 ---------------------------------------------------------------------- webapp/app/js/controllers/cubeEdit.js | 25 ++++ webapp/app/js/controllers/cubeMeasures.js | 130 +++++++++++++++++++- webapp/app/js/directives/directives.js | 29 ++++- webapp/app/js/model/cubeDescModel.js | 6 +- webapp/app/partials/cubeDesigner/measures.html | 77 ++++++++++-- 5 files changed, 250 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/9e2970bc/webapp/app/js/controllers/cubeEdit.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js index b620d7f..e2d0ab5 100755 --- a/webapp/app/js/controllers/cubeEdit.js +++ b/webapp/app/js/controllers/cubeEdit.js @@ -98,6 +98,31 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio return me_columns; }; + $scope.getGroupBYColumns = function () { + //metric from model + var me_columns = []; + var table_columns=[]; + var groupby_columns=[]; + var tableColumns = $scope.getColumnsByTable($scope.metaModel.model.fact_table); + if($scope.metaModel.model.metrics){ + angular.forEach($scope.metaModel.model.metrics,function(metric,index){ + me_columns.push(metric); + }); + } + angular.forEach($scope.cubeMetaFrame.dimensions,function(dimension){ + if(dimension.table==$scope.metaModel.model.fact_table) { + table_columns.push(dimension.column); + } + }); + angular.forEach(me_columns,function(column){ + if(table_columns.indexOf(column)==-1) { + groupby_columns.push(column); + } + }); + + return groupby_columns; + }; + $scope.getExtendedHostColumn = function(){ var me_columns = []; //add cube dimension column for specific measure http://git-wip-us.apache.org/repos/asf/kylin/blob/9e2970bc/webapp/app/js/controllers/cubeMeasures.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/cubeMeasures.js b/webapp/app/js/controllers/cubeMeasures.js index 9dec379..794d2b2 100644 --- a/webapp/app/js/controllers/cubeMeasures.js +++ b/webapp/app/js/controllers/cubeMeasures.js @@ -19,7 +19,9 @@ 'use strict'; KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubesManager,CubeDescModel,SweetAlert) { - + $scope.num=0; + $scope.convertedColumns=[]; + $scope.groupby=[]; $scope.initUpdateMeasureStatus = function(){ $scope.updateMeasureStatus = { isEdit:false, @@ -38,6 +40,31 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes if(!!measure && measure.function.parameter.next_parameter){ $scope.nextPara.value = measure.function.parameter.next_parameter.value; } + if($scope.newMeasure.function.expression=="TOP_N"){ + $scope.convertedColumns=[]; + for(var configuration in $scope.newMeasure.function.configuration) { + var _name=configuration.slice(14); + var item=$scope.newMeasure.function.configuration[configuration]; + var _isFixedLength = item.substring(0,12) === "fixed_length"?"true":"false";//fixed_length:12 + var _isIntLength = item.substring(0,3) === "int"?"true":"false";//fixed_length:12 + var _encoding = item; + var _valueLength = 0 ; + if(_isFixedLength !=="false"){ + _valueLength = item.substring(13,item.length); + _encoding = "fixed_length"; + } + if(_isIntLength!="false"){ + _valueLength = item.substring(4,item.length); + _encoding = "int"; + } + $scope.GroupBy = { + name:_name, + encoding:_encoding, + valueLength:_valueLength, + } + $scope.convertedColumns.push($scope.GroupBy); + }; + } }; @@ -103,9 +130,52 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes $scope.saveNewMeasure = function () { - if ($scope.newMeasure.function.expression === 'TOP_N' && $scope.nextPara.value == "") { - SweetAlert.swal('', '[TOP_N] Group by Column is required', 'warning'); - return false; + if ($scope.newMeasure.function.expression === 'TOP_N' ) { + if($scope.newMeasure.function.parameter.value == ""){ + SweetAlert.swal('', '[TOP_N] ORDER|SUM by Column is required', 'warning'); + return false; + } + if($scope.convertedColumns.length<1){ + SweetAlert.swal('', '[TOP_N] Group by Column is required', 'warning'); + return false; + } + + var hasExisted = []; + + for (var column in $scope.convertedColumns){ + if(hasExisted.indexOf($scope.convertedColumns[column].name)==-1){ + hasExisted.push($scope.convertedColumns[column].name); + } + else{ + SweetAlert.swal('', 'The column named ['+$scope.convertedColumns[column].name+'] already exits.', 'warning'); + return false; + } + if ($scope.convertedColumns[column].encoding == 'int' && ($scope.convertedColumns[column].valueLength < 1 || $scope.convertedColumns[column].valueLength > 8)) { + SweetAlert.swal('', 'int encoding column length should between 1 and 8.', 'warning'); + return false; + } + } + $scope.nextPara.next_parameter={}; + $scope.newMeasure.function.configuration={}; + $scope.groupby($scope.nextPara); + angular.forEach($scope.convertedColumns,function(item){ + var a='topn.encoding.'+item.name; + var encoding=""; + if(item.encoding!=="dict" && item.encoding!=="date"&& item.encoding!=="time"){ + if(item.encoding=="fixed_length" && item.valueLength){ + encoding = "fixed_length:"+item.valueLength; + } + else if(item.encoding=="int" && item.valueLength){ + encoding = "int:"+item.valueLength; + }else{ + encoding = item.encoding; + } + }else{ + encoding = item.encoding; + item.valueLength=0; + } + $scope.newMeasure.function.configuration[a]=encoding; + }); } if ($scope.isNameDuplicated($scope.cubeMetaFrame.measures, $scope.newMeasure) == true) { @@ -143,17 +213,67 @@ KylinApp.controller('CubeMeasuresCtrl', function ($scope, $modal,MetaModel,cubes $scope.nextPara = { "type":"column", "value":"", - "next_parameter":null + "next_parameter":{} } if($scope.newMeasure){ $scope.newMeasure.function.parameter.next_parameter = null; } } + $scope.addNewGroupByColumn = function () { + $scope.nextGroupBy = { + name:null, + encoding:"dict", + valueLength:0, + } + $scope.convertedColumns.push($scope.nextGroupBy); + + }; + + $scope.removeColumn = function(arr,index){ + if (index > -1) { + arr.splice(index, 1); + } + }; + $scope.refreshGroupBy=function (list,index,item) { + var encoding; + var name = item.name; + if(item.encoding=="dict" || item.encoding=="date"|| item.encoding=="time"){ + item.valueLength=0; + } + }; + + $scope.groupby= function (next_parameter){ + if($scope.num<$scope.convertedColumns.length-1){ + next_parameter.value=$scope.convertedColumns[$scope.num].name; + next_parameter.type="column"; + next_parameter.next_parameter={}; + $scope.num++; + $scope.groupby(next_parameter.next_parameter); + } + else{ + next_parameter.value=$scope.convertedColumns[$scope.num].name; + next_parameter.type="column"; + next_parameter.next_parameter=null; + $scope.num=0; + return false; + } + } + $scope.converted = function (next_parameter) { + if (next_parameter != null) { + $scope.groupby.push(next_parameter.value); + converted(next_parameter.next_parameter) + } + else { + $scope.groupby.push(next_parameter.value); + return false; + } + } //map right return type for param $scope.measureReturnTypeUpdate = function(){ if($scope.newMeasure.function.expression == 'TOP_N'){ + $scope.convertedColumns=[]; $scope.newMeasure.function.parameter.type= 'column'; $scope.newMeasure.function.returntype = "topn(100)"; return; http://git-wip-us.apache.org/repos/asf/kylin/blob/9e2970bc/webapp/app/js/directives/directives.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/directives/directives.js b/webapp/app/js/directives/directives.js index 4b83865..f5051e8 100644 --- a/webapp/app/js/directives/directives.js +++ b/webapp/app/js/directives/directives.js @@ -295,7 +295,30 @@ KylinApp.directive('kylinPagination', function ($parse, $q) { }, template: '<li class="parent_li">Value:<b>{{nextpara.value}}</b>, Type:<b>{{ nextpara.type }}</b></li>' + - '<parametertree ng-if="nextpara.next_parameter!=null" nextpara="nextpara.next_parameter"></parameterTree>', + '<parametertree ng-if="nextpara.next_parameter!=null" nextpara="nextpara.next_parameter"></parameterTree>', + 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("groupbytree", function($compile) { + return { + restrict: "E", + transclude: true, + scope: { + nextpara: '=', + }, + template: + '<b>{{nextpara.value}}<b ng-if="nextpara.next_parameter!=null">,</b></b>'+ + '<groupbytree ng-if="nextpara.next_parameter!=null" nextpara="nextpara.next_parameter"></groupbytree>', compile: function(tElement, tAttr, transclude) { var contents = tElement.contents().remove(); var compiledContents; @@ -318,7 +341,9 @@ KylinApp.directive('kylinPagination', function ($parse, $q) { }, template: '<li class="parent_li">SUM|ORDER BY:<b>{{nextpara.value}}</b></b></li>' + - '<li class="parent_li">GROUP BY:<b>{{nextpara.next_parameter.value}}</b></li>', + '<li class="parent_li">Group By:'+ + '<groupbytree nextpara="nextpara.next_parameter"></groupbytree>'+ + '</li>', compile: function(tElement, tAttr, transclude) { var contents = tElement.contents().remove(); var compiledContents; http://git-wip-us.apache.org/repos/asf/kylin/blob/9e2970bc/webapp/app/js/model/cubeDescModel.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/model/cubeDescModel.js b/webapp/app/js/model/cubeDescModel.js index 57d7e6e..c981249 100644 --- a/webapp/app/js/model/cubeDescModel.js +++ b/webapp/app/js/model/cubeDescModel.js @@ -37,7 +37,8 @@ KylinApp.service('CubeDescModel', function () { "type": "constant", "value": "1", "next_parameter":null - } + }, + "configuration":{} } } ], @@ -74,7 +75,8 @@ KylinApp.service('CubeDescModel', function () { "type": "", "value": "", "next_parameter":null - } + }, + "configuration":null } }; http://git-wip-us.apache.org/repos/asf/kylin/blob/9e2970bc/webapp/app/partials/cubeDesigner/measures.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/cubeDesigner/measures.html b/webapp/app/partials/cubeDesigner/measures.html index 53806b4..065b735 100755 --- a/webapp/app/partials/cubeDesigner/measures.html +++ b/webapp/app/partials/cubeDesigner/measures.html @@ -218,19 +218,80 @@ </div> </div> </div> - - <div class="form-group" ng-if="newMeasure.function.expression == 'TOP_N'"> + <!--Group by Column--> + <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 getCommonMetricColumns()" > - <option value=""></option> - </select> + <div class="form-group large-popover" > + <div class="box-body"> + <table style="margin-left:width:92%" + class="table table-hover table-bordered list"> + <thead> + <tr> + <th>ID</th> + <th>Column</th> + <th>Encoding</th> + <th>Length</th> + <th ng-if="state.mode=='edit'"></th> + </tr> + </thead> + + <tbody> + + <tr ng-repeat="groupby_column in convertedColumns track by $index" + ng-class="state.mode=='edit'?'sort-item':''"> + + <td> + <!-- ID --> + <span class="ng-binding" ng-class="state.mode=='edit'?'badge':''">{{($index + 1)}}</span> + </td> + <!--Column Name --> + <td> + <select class="form-control" chosen ng-if="nextPara.type !== 'constant'" required + ng-model="groupby_column.name" + ng-options="column as column for column in getGroupBYColumns()" style="width:323px;"> + <option value="">--Select A Column--</option> + </select> + </td> + <!--Column Encoding --> + <td> + <select ng-if="state.mode=='edit'" style="width:180px;" + chosen ng-model="groupby_column.encoding" + ng-change="refreshGroupBy(convertedColumns,$index,groupby_column)" + ng-options="dt as dt for dt in store.supportedEncoding"> + <option value=""></option> + </select> + <span ng-if="state.mode=='view'">{{groupby_column.encoding}}</span> + + </td> + <td> + <!--Column Length --> + <input type="text" class="form-control" placeholder="Column Length.." ng-if="state.mode=='edit'" + tooltip="group by column length.." tooltip-trigger="focus" + ng-change="refreshGroupBy(convertedColumns,$index,groupby_column);" + ng-disabled="groupby_column.encoding=='dict'||groupby_column.encoding=='date'||groupby_column.encoding=='time'" + ng-model="groupby_column.valueLength" class="form-control"> + + <small class="help-block red" ng-show="state.mode=='edit' && groupby_column.encoding=='int' && (groupby_column.valueLength>8 || groupby_column.valueLength<1)">int encoding column length should between 1 and 8</small> + <span ng-if="state.mode=='view'">{{groupby_column.valueLength}}</span> + </td> + <td ng-if="state.mode=='edit'"> + <button class="btn btn-xs btn-info" + ng-click="removeColumn(convertedColumns, $index)"><i + class="fa fa-minus"></i> + </button> + </td> + </tr> + </tbody> + </table> + </div> + <button class="btn btn-sm btn-info" style="margin-left:10px" + ng-click="addNewGroupByColumn()" ng-show="state.mode=='edit'">New Column<i class="fa fa-plus"></i> + </button> </div> + </div> </div>