You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ma...@apache.org on 2015/05/15 07:22:04 UTC
[35/52] [abbrv] incubator-kylin git commit: add validation for data
model
add validation for data model
Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/3754d620
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/3754d620
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/3754d620
Branch: refs/heads/0.8.0
Commit: 3754d6201a7fd385042d739a5396c53a8f276632
Parents: 725598f
Author: jiazhong <ji...@ebay.com>
Authored: Mon Mar 30 19:46:58 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:36:53 2015 +0800
----------------------------------------------------------------------
webapp/app/css/AdminLTE.css | 2 +-
webapp/app/js/controllers/cubeModel.js | 51 +++++++++++++++-
webapp/app/js/controllers/modelSchema.js | 62 +++++++++++++++++---
webapp/app/js/model/tableModel.js | 23 ++++++++
webapp/app/less/app.less | 16 ++---
webapp/app/less/component.less | 3 +
webapp/app/partials/cubes/cube_detail.html | 2 +-
.../app/partials/modelDesigner/data_model.html | 15 +++--
.../modelDesigner/model_dimensions.html | 53 +++++++++--------
.../app/partials/modelDesigner/model_info.html | 12 ++--
webapp/app/partials/models/model_detail.html | 2 +-
webapp/app/partials/models/model_schema.html | 9 ++-
12 files changed, 185 insertions(+), 65 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/css/AdminLTE.css
----------------------------------------------------------------------
diff --git a/webapp/app/css/AdminLTE.css b/webapp/app/css/AdminLTE.css
index 0b9307d..07b1c88 100644
--- a/webapp/app/css/AdminLTE.css
+++ b/webapp/app/css/AdminLTE.css
@@ -20,7 +20,7 @@ body {
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
- font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ /*font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;*/
font-weight: 400;
overflow-x: hidden;
overflow-y: auto;
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/controllers/cubeModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeModel.js b/webapp/app/js/controllers/cubeModel.js
index 2987905..1622370 100644
--- a/webapp/app/js/controllers/cubeModel.js
+++ b/webapp/app/js/controllers/cubeModel.js
@@ -18,7 +18,7 @@
'use strict';
-KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaModel,SweetAlert,GraphService,$log) {
+KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaModel,SweetAlert,GraphService,$log,TableModel) {
$scope.buildGraph = function (model) {
@@ -95,7 +95,8 @@ KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaMod
// Controller for cube model lookup modal.
var cubeModelLookupModalCtrl = function ($scope, $modalInstance) {
- $scope.ok = function () {
+ $scope.ok = function (lookup_form) {
+ console.log(lookup_form);
$modalInstance.close();
};
@@ -176,4 +177,50 @@ KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,MetaMod
$scope.lookupState.editingIndex = -1;
$scope.newLookup = Lookup();
};
+
+ $scope.checkLookupForm = function(){
+ var errors = [];
+ // null validate
+ for(var i = 0;i<$scope.newLookup.join.primary_key.length;i++){
+ if($scope.newLookup.join.primary_key[i]==='null'){
+ errors.push("Primary Key can't be null.");
+ break;
+ }
+ }
+ for(var i = 0;i<$scope.newLookup.join.foreign_key.length;i++){
+ if($scope.newLookup.join.foreign_key[i]==='null'){
+ errors.push("Foreign Key can't be null.");
+ break;
+ }
+ }
+
+ //column type validate
+ var fact_table = $scope.model.fact_table;
+ var lookup_table = $scope.newLookup.table;
+
+ for(var i = 0;i<$scope.newLookup.join.primary_key.length;i++){
+ var pk_column = $scope.newLookup.join.primary_key[i];
+ var fk_column = $scope.newLookup.join.foreign_key[i];
+ if(pk_column!=='null'&&fk_column!=='null'){
+ var pk_type = TableModel.getColumnType(pk_column,lookup_table);
+ var fk_type = TableModel.getColumnType(fk_column,fact_table);
+ if(pk_type!==fk_type){
+ errors.push(" Column Type incompatible "+pk_column+"["+pk_type+"]"+","+fk_column+"["+fk_type+"].");
+ }
+ }
+ }
+
+ var errorInfo = "";
+ angular.forEach(errors,function(item){
+ errorInfo+="\n"+item;
+ });
+ if(errors.length){
+// SweetAlert.swal('Warning!', errorInfo, '');
+ SweetAlert.swal('', errorInfo, 'warning');
+ return false;
+ }else{
+ return true;
+ }
+
+ };
});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index 4d7b6c1..883bb3a 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -18,7 +18,7 @@
'use strict';
-KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log) {
+KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log,SweetAlert) {
$log.info($scope.model);
@@ -26,17 +26,17 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
$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:null},
- {title: 'Dimensions', src: 'partials/modelDesigner/model_dimensions.html', isComplete: false,form:null},
+ {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'},
{title: 'Measures', src: 'partials/modelDesigner/model_measures.html', isComplete: false,form:null},
{title: 'Settings', src: 'partials/modelDesigner/conditions_settings.html', isComplete: false,form:null}
];
- $scope.formStepMap =[{}]
-
$scope.curStep = $scope.wizardSteps[0];
@@ -95,11 +95,55 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
}
};
- $scope.goToStep = function(stepIndex,form){
- if(form){
- console.log($scope[form]);
- console.log(document.querySelector("form"));
+ $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){
+ return false;
+ }else{
+ //business rule check
+ switch($scope.curStep.form){
+ case 'data_model_form':
+ return $scope.check_data_model();
+ break;
+ default:
+ return true;
+ break;
+ }
+ }
}
+ };
+
+ /*
+ * lookups can't be null
+ */
+ $scope.check_data_model = function(){
+ var errors = [];
+ if(!$scope.model.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;
+ }
+
+ }
+
+
+
+ $scope.goToStep = function(stepIndex){
for(var i=0;i<$scope.wizardSteps.length;i++){
if(i<=stepIndex){
$scope.wizardSteps[i].isComplete = true;
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/js/model/tableModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/tableModel.js b/webapp/app/js/model/tableModel.js
index f482909..55b4e7b 100755
--- a/webapp/app/js/model/tableModel.js
+++ b/webapp/app/js/model/tableModel.js
@@ -138,6 +138,29 @@ KylinApp.service('TableModel', function(ProjectModel,$q,TableService,$log) {
return defer.promise;
};
+
+ this.getColumnType = function(_column,_table){
+ var columns = _this.getColumnsByTable(_table);
+ var type;
+ angular.forEach(columns,function(column){
+ if(_column === column.name){
+ type = column.datatype;
+ return;
+ }
+ });
+ return type;
+ };
+
+ this.getColumnsByTable = function (tableName) {
+ var temp = [];
+ angular.forEach(_this.selectProjectTables, function (table) {
+ if (table.name == tableName) {
+ temp = table.columns;
+ }
+ });
+ return temp;
+ };
+
this.innerSort =function(a, b) {
var nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
if (nameA < nameB) //sort string ascending
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/less/app.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/app.less b/webapp/app/less/app.less
index 9c629d0..8763bb7 100644
--- a/webapp/app/less/app.less
+++ b/webapp/app/less/app.less
@@ -364,14 +364,14 @@ pre {
background: url("../image/icon_table.png") no-repeat;
}
-input.ng-invalid-required {
- border: 1px solid #dd4b39;
-}
-
-input.ng-invalid-required:after {
- content: "*";
- color: red;
-}
+//input.ng-invalid-required {
+// border: 1px solid #dd4b39;
+//}
+//
+//input.ng-invalid-required:after {
+// content: "*";
+// color: red;
+//}
.nav-pills>li {
cursor: pointer;
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/less/component.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/component.less b/webapp/app/less/component.less
index ee28e84..14a6fe8 100644
--- a/webapp/app/less/component.less
+++ b/webapp/app/less/component.less
@@ -968,4 +968,7 @@ Angular 1.2.0 Animation
//form validate
.has-feedback{
+}
+.highlight-bule{
+ color:#428bca !important;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/cubes/cube_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubes/cube_detail.html b/webapp/app/partials/cubes/cube_detail.html
index f5652eb..93084e3 100755
--- a/webapp/app/partials/cubes/cube_detail.html
+++ b/webapp/app/partials/cubes/cube_detail.html
@@ -47,7 +47,7 @@
<a href="" ng-click="cube.visiblePage='hbase';getHbaseInfo(cube)">HBase</a>
</li>
<li class="dropdown" ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission(cube, permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, permissions.OPERATION.mask)">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">
+ <a class="dropdown-toggle highlight-bule" data-toggle="dropdown" href="#" aria-expanded="true">
<i class="fa fa-cubes">Action</i> <span class="caret"></span>
</a>
<ul class="dropdown-menu">
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/data_model.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/data_model.html b/webapp/app/partials/modelDesigner/data_model.html
index c8cc5a7..79c6533 100644
--- a/webapp/app/partials/modelDesigner/data_model.html
+++ b/webapp/app/partials/modelDesigner/data_model.html
@@ -17,7 +17,7 @@
-->
<div ng-controller="CubeModelCtrl">
- <ng-form name="model_form">
+ <ng-form name="forms.data_model_form">
<!-- Fact Table Name -->
<div class="form-group">
@@ -25,9 +25,11 @@
<label class="col-xs-12 col-sm-2 concube.detailtrol-label no-padding-right font-color-default">
<b>Fact Table</b>
</label>
- <div class="col-xs-12 col-sm-6">
+ <div class="col-xs-12 col-sm-6" ng-class="forms.data_model_form.innerform.typeahead.$invalid?'has-error':''">
<typeahead ng-if="state.mode=='edit'" items="tableModel.selectProjectTables" prompt="Fact Table Name"
title="name" model="model.fact_table" required="true"></typeahead>
+ <small class="help-block" ng-show="forms.data_model_form.innerform.typeahead.$error.required">The fact table is required</small>
+
<span ng-if="state.mode=='view'">{{model.fact_table}}</span>
</div>
</div>
@@ -109,12 +111,13 @@
<div class="col-xs-8">
<ng-form name="lookup_form">
<!--Table Name-->
- <div class="form-group">
+ <div class="form-group" ng-class="lookup_form.innerform.typeahead.$invalid?'has-error':''">
<div class="row">
<label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Lookup Table Name</b></label>
<div class="col-xs-12 col-sm-6">
- <typeahead items="tableModel.selectProjectTables" prompt="Lookup Table Name" title="name" model="newLookup.table"></typeahead>
+ <typeahead items="tableModel.selectProjectTables" prompt="Lookup Table Name" required="true" title="name" model="newLookup.table"></typeahead>
</div>
+ <small class="help-block" ng-show="lookup_form.innerform.typeahead.$error.required">Table name required</small>
</div>
</div>
@@ -123,7 +126,7 @@
<div class="row">
<label class="col-sm-3 control-label font-color-default"><b>Join Type</b></label>
<div class="col-sm-6">
- <select class="form-control" chosen ng-model="newLookup.join.type"
+ <select class="form-control" chosen ng-model="newLookup.join.type"
ng-options="joinType.value as joinType.name for joinType in cubeConfig.joinTypes">
<option value=""></option>
</select>
@@ -192,7 +195,7 @@
</div>
</div>
<div class="modal-footer">
- <button class="btn btn-primary" ng-disabled="lookup_form.$invalid || !newLookup.join.primary_key.length" ng-click="ok()">OK</button>
+ <button class="btn btn-primary" ng-disabled="lookup_form.$invalid || !newLookup.join.primary_key.length" ng-click="checkLookupForm()?ok():''">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/model_dimensions.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_dimensions.html b/webapp/app/partials/modelDesigner/model_dimensions.html
index 62af873..10a8d77 100644
--- a/webapp/app/partials/modelDesigner/model_dimensions.html
+++ b/webapp/app/partials/modelDesigner/model_dimensions.html
@@ -32,33 +32,34 @@
</div>
</div>
+ <ng-form name="model_dimensions" novalidate>
<!-- VIEW MODE -->
- <table class="table table-striped table-hover" ng-if="state.mode=='view'&&model.dimensions.length > 0">
- <thead>
- <tr>
- <th>ID</th>
- <th>Table Name</th>
- <th>Columns</th>
- </tr>
- </thead>
- <tbody class="cube-dimension">
- <tr ng-repeat="dimension in model.dimensions | filter:dimState.filter track by $index">
- <!--ID -->
- <td>
- <b>{{dimension.id = ($index + 1)}}</b>
- </td>
- <!--Name -->
- <td>
- <span>{{dimension.table}}</span>
- </td>
- <!--Table Name -->
- <td>
- <span>{{dimension.columns}}</span>
- </td>
- </tr>
- </tbody>
- </table>
-
+ <table class="table table-striped table-hover" ng-if="state.mode=='view'&&model.dimensions.length > 0">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Table Name</th>
+ <th>Columns</th>
+ </tr>
+ </thead>
+ <tbody class="cube-dimension">
+ <tr ng-repeat="dimension in model.dimensions | filter:dimState.filter track by $index">
+ <!--ID -->
+ <td>
+ <b>{{dimension.id = ($index + 1)}}</b>
+ </td>
+ <!--Name -->
+ <td>
+ <span>{{dimension.table}}</span>
+ </td>
+ <!--Table Name -->
+ <td>
+ <span>{{dimension.columns}}</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </ng-form>
<div ng-if="state.mode=='edit'" class="form-group model-dimension-edit" style="width: 100%">
<h4 style="margin-left:42px">Dimensions</h4>
<table style="margin-left:42px; width:92%"
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/modelDesigner/model_info.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_info.html b/webapp/app/partials/modelDesigner/model_info.html
index ca7e231..21a8185 100644
--- a/webapp/app/partials/modelDesigner/model_info.html
+++ b/webapp/app/partials/modelDesigner/model_info.html
@@ -19,7 +19,7 @@
<div class="row">
<div class="col-xs-8">
<!--Project-->
- <ng-form name="model_info_form" novalidate>
+ <ng-form name="forms.model_info_form" novalidate>
<div class="form-group">
<div class="row">
<label class="col-xs-3 control-label no-padding-right">
@@ -28,11 +28,11 @@
</a>
<b ng-if="state.mode=='view'" class="font-color-default">Project</b>
</label>
- <div class="col-xs-6" ng-class="model_info_form.project_name.$invalid?'has-error':model_info_form.project_name.$dirty?'has-success':''">
+ <div class="col-xs-6" ng-class="forms.model_info_form.project_name.$invalid?'has-error':''">
<!--edit-->
<input ng-if="state.mode=='edit'" required name="project_name" type="text" class="form-control"
ng-model="model.project"/>
- <small class="help-block" ng-show="model_info_form.project_name.$error.required">The project is required</small>
+ <small class="help-block" ng-show="forms.model_info_form.project_name.$error.required">The project is required</small>
<!--view-->
<span ng-if="state.mode=='view'">
@@ -49,15 +49,15 @@
<b>Model Name</b>
</label>
- <div class="col-xs-12 col-sm-6" ng-class="model_info_form.model_name.$invalid?'has-error':model_info_form.model_name.$dirty?'has-success':''">
+ <div class="col-xs-12 col-sm-6" ng-class="forms.model_info_form.model_name.$invalid?'has-error':''">
<!-- edit -->
<input ng-if="state.mode=='edit'" name="model_name" type="text" class="form-control"
ng-model="model.name" required
placeholder="You can use letters, numbers, and '_'"
ng-maxlength=100 ng-pattern="/^\w+$/" />
- <small class="help-block" ng-show="model_info_form.model_name.$error.required && model_info_form.model_name.$dirty">Model name is required.</small>
- <small class="help-block" ng-show="model_info_form.model_name.$invalid && model_info_form.model_name.$dirty && !model_info_form.model_name.$error.required"> Model name is invalid.</small>
+ <small class="help-block" ng-show="forms.model_info_form.model_name.$error.required && forms.model_info_form.model_name.$dirty">Model name is required.</small>
+ <small class="help-block" ng-show="forms.model_info_form.model_name.$invalid && forms.model_info_form.model_name.$dirty && !forms.model_info_form.model_name.$error.required"> Model name is invalid.</small>
<span ng-if="state.mode=='view'">{{model.name}}</span>
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/models/model_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_detail.html b/webapp/app/partials/models/model_detail.html
index 1808d5e..e26c29f 100644
--- a/webapp/app/partials/models/model_detail.html
+++ b/webapp/app/partials/models/model_detail.html
@@ -30,7 +30,7 @@
<a href="" ng-click="model.visiblePage='json_model';">JSON</a>
</li>
<li class="dropdown" ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission(model, permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, permissions.OPERATION.mask)">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">
+ <a class="dropdown-toggle highlight-bule" data-toggle="dropdown" href="#" aria-expanded="true">
<i class="fa fa-star"> Action </i> <span class="caret"></span>
</a>
<ul class="dropdown-menu">
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/3754d620/webapp/app/partials/models/model_schema.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_schema.html b/webapp/app/partials/models/model_schema.html
index ac607e6..86a3196 100644
--- a/webapp/app/partials/models/model_schema.html
+++ b/webapp/app/partials/models/model_schema.html
@@ -28,7 +28,7 @@
<ul class="wizard-steps">
<li ng-repeat="step in wizardSteps"
class="{{step==curStep?'active':''}} {{step.isComplete?'complete':''}}">
- <span style="cursor:pointer;" ng-click="goToStep($index,curStep.form)" class="step">{{step.step = ($index + 1)}}</span>
+ <span style="cursor:pointer;" ng-click="checkForm()?goToStep($index):''" class="step">{{step.step = ($index + 1)}}</span>
<span class="title">{{step.title}}</span>
</li>
</ul>
@@ -40,18 +40,17 @@
<hr/>
<div class="wizard-actions">
<div class="row">
- <div class="col-xs-8" style="display:none;">
- <p style="color: #808080;text-align: left;"><b>Note:</b> inputs with <span style="color: lightblue">light blue</span> border are mandatory.</p>
+ <div class="col-xs-8" style="display:block;">
<div>
<a href="models" class="pull-left"><i class="fa fa-arrow-left"></i> Back to My Models</a>
</div>
</div>
<div class="col-xs-4 pull-right">
- <button class="btn btn-prev" ng-click="preView()" ng-show="curStep.title!='Model Info'">
+ <button class="btn btn-prev" ng-click="checkForm()?preView():''" ng-show="curStep.title!='Model Info'">
<i class="ace-icon fa fa-arrow-left"></i>
Prev
</button>
- <button id="nextButton" class="btn btn-success btn-next" ng-click="nextView()" ng-disabled="design_form.$invalid"
+ <button id="nextButton" class="btn btn-success btn-next" ng-click="checkForm()?nextView():''" ng-disabled="design_form.$invalid"
ng-show="curStep.title!='Settings'">
Next
<i class="ace-icon fa fa-arrow-right icon-on-right"></i>