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:21:48 UTC
[19/52] [abbrv] incubator-kylin git commit: show models list page
show models list page
Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/7b526242
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/7b526242
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/7b526242
Branch: refs/heads/0.8.0
Commit: 7b526242ce17ec6f59ecf1e87b44d0bf309bc58a
Parents: 286e520
Author: jiazhong <ji...@ebay.com>
Authored: Fri Mar 13 16:28:25 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:35:49 2015 +0800
----------------------------------------------------------------------
.../apache/kylin/rest/service/ModelService.java | 1 +
webapp/app/index.html | 16 +
webapp/app/js/controllers/cubeModel.js | 25 +-
webapp/app/js/controllers/modelDimensions.js | 402 +++++++++++++++++++
webapp/app/js/controllers/modelMeasures.js | 27 ++
webapp/app/js/controllers/modelRefresh.js | 23 ++
webapp/app/js/controllers/modelSchema.js | 209 ++++++++++
webapp/app/js/controllers/models.js | 79 ++++
webapp/app/js/model/jobListModel.js | 4 +
webapp/app/js/model/metaModel.js | 3 +
webapp/app/js/model/modelConfig.js | 26 ++
webapp/app/js/model/modelList.js | 52 +++
webapp/app/js/services/models.js | 26 ++
webapp/app/js/services/tree.js | 71 ++--
webapp/app/js/services/users.js | 6 +-
webapp/app/less/app.less | 6 +-
.../app/partials/cubeDesigner/data_model.html | 199 ---------
webapp/app/partials/header.html | 4 +-
.../app/partials/modelDesigner/data_model.html | 199 +++++++++
.../app/partials/modelDesigner/incremental.html | 94 +++++
.../modelDesigner/model_dimensions.html | 354 ++++++++++++++++
.../partials/modelDesigner/model_measures.html | 185 +++++++++
webapp/app/partials/models/model_detail.html | 43 ++
webapp/app/partials/models/model_edit.html | 34 ++
webapp/app/partials/models/model_schema.html | 68 ++++
webapp/app/partials/models/models.html | 117 ++++++
webapp/app/routes.json | 8 +
27 files changed, 2038 insertions(+), 243 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
index ddf2594..093efe3 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
@@ -58,6 +58,7 @@ public class ModelService extends BasicService {
} else {
//TO-DO
// models = listAllModels(projectName);
+ models=Collections.emptyList();
}
List<DataModelDesc> filterModels = new ArrayList();
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/index.html
----------------------------------------------------------------------
diff --git a/webapp/app/index.html b/webapp/app/index.html
index 44021a9..9e7317f 100644
--- a/webapp/app/index.html
+++ b/webapp/app/index.html
@@ -127,11 +127,16 @@
<script src="js/services/tree.js"></script>
<script src="js/services/users.js"></script>
<script src="js/services/ngLoading.js"></script>
+<!--New GUI-->
+<script src="js/services/models.js"></script>
<script src="js/model/cubeConfig.js"></script>
<script src="js/model/jobConfig.js"></script>
<script src="js/model/projectConfig.js"></script>
<script src="js/model/tableConfig.js"></script>
+<!--New GUI-->
+<script src="js/model/modelConfig.js"></script>
+
<script src="js/model/cubeDescModel.js"></script>
<script src="js/model/metaModel.js"></script>
<script src="js/model/projectModel.js"></script>
@@ -139,6 +144,9 @@
<script src="js/model/cubeListModel.js"></script>
<script src="js/model/jobListModel.js"></script>
+<!--New GUI-->
+<script src="js/model/modelList.js"></script>
+
<script src="js/controllers/page.js"></script>
<script src="js/controllers/index.js"></script>
<script src="js/controllers/access.js"></script>
@@ -158,6 +166,14 @@
<script src="js/controllers/cubeFilter.js"></script>
<script src="js/controllers/cubeRefresh.js"></script>
<script src="js/controllers/cubeAdvanceSetting.js"></script>
+<!--New GUI-->
+<script src="js/controllers/modelSchema.js"></script>
+<script src="js/controllers/modelDimensions.js"></script>
+<script src="js/controllers/modelRefresh.js"></script>
+
+<!--New GUI-->
+<script src="js/controllers/models.js"></script>
+
<!-- endref -->
<!-- ref:remove -->
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/cubeModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeModel.js b/webapp/app/js/controllers/cubeModel.js
index 2874742..038f7be 100644
--- a/webapp/app/js/controllers/cubeModel.js
+++ b/webapp/app/js/controllers/cubeModel.js
@@ -18,7 +18,28 @@
'use strict';
-KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,ModelService,MetaModel,SweetAlert,$log) {
+KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,ModelService,MetaModel,SweetAlert,CubeGraphService,$log) {
+
+
+ $scope.buildGraph = function (cube) {
+ CubeGraphService.buildTree(cube);
+ };
+ $scope.cleanStatus = function(model){
+
+ if (!model)
+ {
+ return;
+ }
+ var newModel = jQuery.extend(true, {}, model);
+ delete newModel.visiblePage;
+ delete newModel.showDetail;
+
+ angular.forEach(newModel.dimensions, function(dimension, index){
+ delete dimension.status;
+ });
+
+ return newModel;
+ };
$scope.cubeConfig = cubeConfig;
var DataModel = function () {
@@ -49,7 +70,7 @@ KylinApp.controller('CubeModelCtrl', function ($scope, $modal,cubeConfig,ModelSe
$scope.newLookup = Lookup();
- var lookupList = $scope.metaModel.model.lookups;
+ var lookupList = $scope.model.lookups;
$scope.openLookupModal = function () {
var modalInstance = $modal.open({
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/modelDimensions.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelDimensions.js b/webapp/app/js/controllers/modelDimensions.js
new file mode 100644
index 0000000..aa197e6
--- /dev/null
+++ b/webapp/app/js/controllers/modelDimensions.js
@@ -0,0 +1,402 @@
+/*
+ * 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('ModelDimensionsCtrl', function ($scope, $modal,MetaModel) {
+
+ // Available columns list derived from cube data model.
+ $scope.availableColumns = {};
+
+ // Columns selected and disabled status bound to UI, group by table.
+ $scope.selectedColumns = {};
+
+ // Available tables cache: 1st is the fact table, next are lookup tables.
+ $scope.availableTables = [];
+
+
+ /**
+ * Helper func to get columns that dimensions based on, three cases:
+ * 1. normal dimension: column array.
+ * 2. hierarchy dimension: column array, the array index is the hierarchy level.
+ * 3. derived dimension: derived columns array.
+ * TODO new cube schema change
+ */
+ var dimCols = function (dim) {
+ var referredCols = [];
+
+ // Case 3.
+ if (dim.derived && dim.derived.length) {
+ referredCols = referredCols.concat(dim.derived);
+ }
+
+ // Case 2.
+ if (dim.hierarchy && dim.column.length) {
+ referredCols = referredCols.concat(dim.column);
+ }
+
+ // Case 1.
+ if (!dim.derived && !dim.hierarchy) {
+ referredCols.push(dim.column);
+ }
+
+ return referredCols;
+ };
+
+ // Dump available columns plus column table name, whether is from lookup table.
+ $scope.initColumns = function () {
+ var factTable = $scope.model.fact_table;
+
+ // At first dump the columns of fact table.
+ var cols = $scope.getColumnsByTable(factTable);
+
+ // Initialize selected available.
+ var factAvailable = {};
+ var factSelectAvailable = {};
+
+ for (var i = 0; i < cols.length; i++) {
+ cols[i].table = factTable;
+ cols[i].isLookup = false;
+
+ factAvailable[cols[i].name] = cols[i];
+
+ // Default not selected and not disabled.
+ factSelectAvailable[cols[i].name] = {selected: false, disabled: false};
+ }
+
+ $scope.availableColumns[factTable] = factAvailable;
+ $scope.selectedColumns[factTable] = factSelectAvailable;
+ $scope.availableTables.push(factTable);
+
+ // Then dump each lookup tables.
+ var lookups = $scope.model.lookups;
+
+ for (var j = 0; j < lookups.length; j++) {
+ var cols2 = $scope.getColumnsByTable(lookups[j].table);
+
+ // Initialize selected available.
+ var lookupAvailable = {};
+ var lookupSelectAvailable = {};
+
+ for (var k = 0; k < cols2.length; k++) {
+ cols2[k].table = lookups[j].table;
+ cols2[k].isLookup = true;
+
+ lookupAvailable[cols2[k].name] = cols2[k];
+
+ // Default not selected and not disabled.
+ lookupSelectAvailable[cols2[k].name] = {selected: false, disabled: false};
+ }
+
+ $scope.availableColumns[lookups[j].table] = lookupAvailable;
+ $scope.selectedColumns[lookups[j].table] = lookupSelectAvailable;
+ $scope.availableTables.push(lookups[j].table);
+ }
+ };
+
+ // Check column status: selected or disabled based on current cube dimensions.
+ $scope.initColumnStatus = function () {
+ angular.forEach($scope.model.dimensions, function (dim) {
+ var cols = dimCols(dim);
+
+ angular.forEach(cols, function (colName) {
+ $scope.selectedColumns[dim.table][colName] = {selected: true, disabled: true};
+ });
+ });
+ };
+
+ // Initialize data for columns widget in auto-gen when add/edit cube.
+ if ($scope.state.mode == 'edit') {
+ $scope.initColumns();
+ }
+
+ // Initialize params for add/edit dimension.
+ $scope.dimState = {
+ editing: false,
+ editingIndex: -1,
+ filter: ''
+ };
+
+ // Init the dimension, dimension name default as the column key. TODO new cube schema change.
+ var Dimension = function (table, selectedCols, dimType) {
+ var origin = {name: '', table: table,hierarchy:false,derived:null,column:null};
+
+ switch (dimType) {
+ case 'normal':
+ // Default name as 1st column name.
+ if (table && selectedCols.length) {
+ origin.name = table + '.' + selectedCols[0];
+ }
+
+ origin.column = selectedCols;
+ break;
+
+ case 'derived':
+ if (table && selectedCols.length) {
+ origin.name = table + '_derived';
+ }
+
+ origin.derived = selectedCols;
+ break;
+
+ case 'hierarchy':
+ if (table && selectedCols.length) {
+ origin.name = table + '_hierarchy';
+ }
+
+ origin.hierarchy = true;
+ origin.column = selectedCols;
+ break;
+ }
+
+ return origin;
+ };
+
+ // Since old schema may be both derived and hierarchy. TODO new cube schema change.
+ $scope.getDimType = function (dim) {
+ var types = [];
+
+ if (dim.derived && dim.derived.length) {
+ types.push('derived');
+ }
+
+ if (dim.hierarchy && dim.column.length) {
+ types.push('hierarchy');
+ }
+
+ if (!types.length) {
+ types.push('normal');
+ }
+
+ return types;
+ };
+
+ var dimList = $scope.model.dimensions;
+
+ // Open add/edit dimension modal.
+ $scope.openDimModal = function (dimType) {
+ var modalInstance = $modal.open({
+ templateUrl: 'addEditDimension.html',
+ controller: cubeDimModalCtrl,
+ backdrop: 'static',
+ scope: $scope,
+ resolve: {
+ dimType: function () {
+ // For old schema compatibility, convert into array here. TODO new cube schema change.
+ return angular.isArray(dimType) ? dimType : [dimType];
+ }
+ }
+ });
+
+ modalInstance.result.then(function () {
+ if (!$scope.dimState.editing) {
+ $scope.doneAddDim();
+ } else {
+ $scope.doneEditDim();
+ }
+
+ }, function () {
+ $scope.cancelDim();
+ });
+ };
+
+ // Controller for cube dimension add/edit modal.
+ var cubeDimModalCtrl = function ($scope, $modalInstance, dimType) {
+ $scope.dimType = dimType;
+
+ $scope.ok = function () {
+ $modalInstance.close();
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ };
+
+ $scope.addDim = function (dimType) {
+ $scope.newDimension = Dimension('', [], dimType);
+
+ $scope.openDimModal(dimType);
+ };
+
+ $scope.editDim = function (dim) {
+ $scope.dimState.editingIndex = dimList.indexOf(dim);
+ $scope.dimState.editing = true;
+
+ // Make a copy of model will be editing.
+ $scope.newDimension = angular.copy(dim);
+
+ $scope.openDimModal($scope.getDimType(dim));
+ };
+
+ $scope.doneAddDim = function () {
+ // Push new dimension which bound user input data.
+ dimList.push(angular.copy($scope.newDimension));
+
+ $scope.resetParams();
+ };
+
+ $scope.doneEditDim = function () {
+ // Copy edited model to destination model.
+ angular.copy($scope.newDimension, dimList[$scope.dimState.editingIndex]);
+
+ $scope.resetParams();
+ };
+
+ $scope.cancelDim = function () {
+ $scope.resetParams();
+ };
+
+ $scope.removeDim = function (dim) {
+ dimList.splice(dimList.indexOf(dim), 1);
+ };
+
+ $scope.resetParams = function () {
+ $scope.dimState.editing = false;
+ $scope.dimState.editingIndex = -1;
+
+ $scope.newDimension = {};
+ };
+
+ // Open auto-gen dimension modal.
+ $scope.openAutoGenModal = function (dimType) {
+ // Init columns status.
+ $scope.initColumnStatus();
+
+ var modalInstance = $modal.open({
+ templateUrl: 'autoGenDimension.html',
+ controller: cubeAutoGenDimModalCtrl,
+ backdrop: 'static',
+ scope: $scope
+ });
+
+ modalInstance.result.then(function () {
+ $scope.autoGenDims();
+ }, function () {
+ $scope.resetGenDims();
+ });
+ };
+
+ // Controller for cube dimension auto-gen modal.
+ var cubeAutoGenDimModalCtrl = function ($scope, $modalInstance) {
+ $scope.ok = function () {
+ $modalInstance.close();
+ };
+
+ $scope.cancel = function () {
+ $modalInstance.dismiss('cancel');
+ };
+ };
+
+ // Helper func to get the selected status in auto gen.
+ $scope.getSelectedCols = function () {
+ var selectedCols = {};
+
+ angular.forEach($scope.selectedColumns, function (value, table) {
+ angular.forEach(value, function (status, colName) {
+ if (status.selected && !status.disabled) {
+ if (!selectedCols[table]) {
+ selectedCols[table] = [];
+ }
+
+ selectedCols[table].push(colName);
+ }
+ });
+ });
+
+ return selectedCols;
+ };
+
+ // Auto generate dimensions.
+ $scope.autoGenDims = function () {
+ var selectedCols = $scope.getSelectedCols();
+
+ angular.forEach(selectedCols, function (cols, table) {
+ if ($scope.model.fact_table == table) {
+ // Fact table: for each selected column, create one normal dimension.
+ for (var i = 0; i < cols.length; i++) {
+ dimList.push(Dimension(table, [cols[i]], 'normal'));
+ }
+ } else {
+ // Per lookup table, create one derived dimension for all its selected columns;
+ if (cols.length) {
+ dimList.push(Dimension(table, cols, 'derived'));
+ }
+ }
+ });
+ };
+
+ // Just reset the selected status of columns.
+ $scope.resetGenDims = function () {
+ var selectedCols = $scope.getSelectedCols();
+
+ angular.forEach(selectedCols, function (cols, table) {
+ for (var i = 0; i < cols.length; i++) {
+ $scope.selectedColumns[table][cols[i]].selected = false;
+ }
+ });
+ };
+
+ // Check whether there is column conflicts.
+ $scope.dimConflicts = [];
+
+ $scope.$watch('cubeMetaFrame.dimensions', function (newVal, oldVal) {
+ if (!newVal || !newVal.length) {
+ return;
+ }
+
+ var referredCols = {};
+
+ angular.forEach(newVal, function (curDim) {
+ var table = curDim.table;
+ var cols = dimCols(curDim);
+
+ for (var i = 0; i < cols.length; i++) {
+ var key = table + '.' + cols[i];
+
+ if (!referredCols[key]) {
+ referredCols[key] = [];
+ }
+
+ referredCols[key].push({id: curDim.id, name: curDim.name});
+ }
+ });
+
+ var conflicts = [];
+
+ angular.forEach(referredCols, function (dims, key) {
+ if (dims.length > 1) {
+ // More than 1 dimensions has referred this column.
+ var colInfo = key.split('.');
+ conflicts.push({table: colInfo[0], column: colInfo[1], dims: dims});
+ }
+ });
+
+ $scope.dimConflicts = conflicts;
+ }, true);
+
+
+
+ if ($scope.state.mode == 'edit') {
+ $scope.$on('$destroy', function () {
+ // $scope.dimensionsAdapter();
+ // Emit dimensions edit event in order to re-generate row key.
+ $scope.$emit('DimensionsEdited');
+ });
+ }
+});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/modelMeasures.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelMeasures.js b/webapp/app/js/controllers/modelMeasures.js
new file mode 100644
index 0000000..01cd35a
--- /dev/null
+++ b/webapp/app/js/controllers/modelMeasures.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/**
+ * Created by jiazhong on 2015/3/13.
+ */
+
+'use strict';
+
+KylinApp.controller('ModelMeasuresCtrl', function ($scope) {
+
+});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/modelRefresh.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelRefresh.js b/webapp/app/js/controllers/modelRefresh.js
new file mode 100644
index 0000000..04b5bf7
--- /dev/null
+++ b/webapp/app/js/controllers/modelRefresh.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('ModelRefreshCtrl', function ($scope, $modal,cubeConfig,ModelService,MetaModel) {
+
+});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
new file mode 100644
index 0000000..638e119
--- /dev/null
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -0,0 +1,209 @@
+/*
+ * 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('ModelSchemaCtrl', function ($scope, QueryService, UserService, ProjectService, AuthenticationService,$filter,ModelService,MetaModel,CubeDescModel,CubeList,TableModel,ProjectModel,$log) {
+
+ $log.info($scope.model);
+
+ $scope.projects = [];
+ $scope.newDimension = null;
+ $scope.newMeasure = null;
+
+
+ $scope.wizardSteps = [
+ {title: 'Data Model', src: 'partials/modelDesigner/data_model.html', isComplete: false},
+ {title: 'Dimensions', src: 'partials/modelDesigner/model_dimensions.html', isComplete: false},
+ {title: 'Measures', src: 'partials/modelDesigner/model_measures.html', isComplete: false},
+ {title: 'Refresh Setting', src: 'partials/modelDesigner/incremental.html', isComplete: false}
+ ];
+
+ $scope.curStep = $scope.wizardSteps[0];
+
+
+ // ~ init
+ if (!$scope.state) {
+ $scope.state = {mode: "view"};
+ }
+
+ $scope.$watch('cubeMetaFrame', function (newValue, oldValue) {
+ if(!newValue){
+ return;
+ }
+ if ($scope.cubeMode=="editExistCube"&&newValue && !newValue.project) {
+ initProject();
+ }
+
+ });
+
+ // ~ public methods
+ $scope.filterProj = function(project){
+ 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.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
+
+
+ switch($scope.newMeasure.function.expression){
+ case "SUM":
+ if(colType==="smallint"||colType==="int"||colType==="bigint"){
+ $scope.newMeasure.function.returntype= 'bigint';
+ }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);
+ if (index > -1) {
+ arr.splice(index, 1);
+ }
+ };
+
+ $scope.open = function ($event) {
+ $event.preventDefault();
+ $event.stopPropagation();
+
+ $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.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];
+
+ AuthenticationService.ping(function (data) {
+ UserService.setCurUser(data);
+ });
+ }
+ };
+
+ $scope.goToStep = function(stepIndex){
+ 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);
+ });
+ }
+ }
+
+ // ~ private methods
+ function initProject() {
+ ProjectService.list({}, function (projects) {
+ $scope.projects = projects;
+
+ var cubeName = (!!$scope.routeParams.cubeName)? $scope.routeParams.cubeName:$scope.state.cubeName;
+ if (cubeName) {
+ var projName = null;
+ if(ProjectModel.getSelectedProject()){
+ projName=ProjectModel.getSelectedProject();
+ }else{
+ angular.forEach($scope.projects, function (project, index) {
+ angular.forEach(project.realizations, function (unit, index) {
+ if (!projName && unit.type=="CUBE"&&unit.realization === cubeName) {
+ projName = project.name;
+ }
+ });
+ });
+ }
+
+ if(!ProjectModel.getSelectedProject()){
+ ProjectModel.setSelectedProject(projName);
+ TableModel.aceSrcTbLoaded();
+ }
+
+ $scope.cubeMetaFrame.project = projName;
+ }
+
+ angular.forEach($scope.projects, function (project, index) {
+ $scope.listAccess(project, 'ProjectInstance');
+ });
+ });
+ }
+});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/controllers/models.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/models.js b/webapp/app/js/controllers/models.js
new file mode 100644
index 0000000..1777723
--- /dev/null
+++ b/webapp/app/js/controllers/models.js
@@ -0,0 +1,79 @@
+/*
+ * 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('ModelsCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService,SweetAlert,loadingRequest,$log,modelConfig,ProjectModel,ModelService,MetaModel,ModelList) {
+ $scope.modelList = ModelList;
+ $scope.modelConfig = modelConfig;
+ ModelList.removeAll();
+ $scope.loading = false;
+ $scope.action = {};
+
+ $scope.listParams={
+ cubeName: $routeParams.cubeName,
+ projectName: $routeParams.projectName
+ };
+
+ $scope.list = function (offset, limit) {
+ if(!$scope.projectModel.projects.length){
+ return [];
+ }
+ offset = (!!offset) ? offset : 0;
+ limit = (!!limit) ? limit : 20;
+
+ var queryParam = {offset: offset, limit: limit};
+ if ($scope.listParams.modelName) {
+ queryParam.modelName = $scope.listParams.modelName;
+ }
+ queryParam.projectName = $scope.projectModel.selectedProject;
+
+ $scope.loading = true;
+
+ var defer = $q.defer();
+ return ModelList.list(queryParam).then(function(resp){
+ $scope.loading = false;
+ defer.resolve(resp);
+ defer.promise;
+ },function(resp){
+ $scope.loading = false;
+ defer.resolve([]);
+ defer.promise;
+ });
+ };
+
+
+ $scope.loadDetail = function (model) {
+ $log.info(model);
+ };
+
+
+ $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
+ if(newValue!=oldValue||newValue==null){
+ ModelList.removeAll();
+ $scope.reload();
+ }
+
+ });
+ $scope.reload = function () {
+ // trigger reload action in pagination directive
+ $scope.action.reload = !$scope.action.reload;
+ };
+
+ });
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/model/jobListModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/jobListModel.js b/webapp/app/js/model/jobListModel.js
index 764791a..404bf20 100755
--- a/webapp/app/js/model/jobListModel.js
+++ b/webapp/app/js/model/jobListModel.js
@@ -16,6 +16,10 @@
* limitations under the License.
*/
+/*
+ *jobListModel will manage data in list job page
+ */
+
KylinApp.service('JobList',function(JobService,$q){
var _this = this;
this.jobs=[];
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/model/metaModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/metaModel.js b/webapp/app/js/model/metaModel.js
index a21c83c..021dda7 100644
--- a/webapp/app/js/model/metaModel.js
+++ b/webapp/app/js/model/metaModel.js
@@ -16,6 +16,9 @@
* limitations under the License.
*/
+/**
+ *MetaModel will manage model info of cube
+ */
KylinApp.service('MetaModel',function(){
//data model when edit model
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/model/modelConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/modelConfig.js b/webapp/app/js/model/modelConfig.js
new file mode 100644
index 0000000..e910ce5
--- /dev/null
+++ b/webapp/app/js/model/modelConfig.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+*/
+
+KylinApp.constant('modelConfig', {
+// models config
+ theaditems : [
+ {attr: 'name', name: 'Name'},
+ {attr: 'factTable', name: 'Fact Table'},
+ {attr: 'date_modified', name: 'Date Modified'}
+ ]
+ });
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/model/modelList.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/modelList.js b/webapp/app/js/model/modelList.js
new file mode 100644
index 0000000..30e9b70
--- /dev/null
+++ b/webapp/app/js/model/modelList.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+*/
+
+KylinApp.service('ModelList',function(ModelService,$q){
+ var models=[];
+ var _this = this;
+
+ this.list = function(queryParam){
+
+ var defer = $q.defer();
+ ModelService.list(queryParam, function (_models) {
+ angular.forEach(_models, function (models, index) {
+ if(models.name){
+// $scope.listAccess(models, 'modelsInstance');
+ }
+ });
+ _models = _.filter(_models,function(models){return models.name!=undefined});
+ _this.models = _this.models.concat(_models);
+ defer.resolve(_this.models.length);
+ },function(){
+ defer.reject("Failed to load models");
+ });
+ return defer.promise;
+
+ };
+
+ this.removemodels = function(models){
+ var modelsIndex = _this.models.indexOf(models);
+ if (modelsIndex > -1) {
+ _this.models.splice(modelsIndex, 1);
+ }
+ }
+
+ this.removeAll = function(){
+ _this.models=[];
+ };
+});
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/services/models.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/models.js b/webapp/app/js/services/models.js
new file mode 100644
index 0000000..7698e49
--- /dev/null
+++ b/webapp/app/js/services/models.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+*/
+
+KylinApp.factory('ModelService', ['$resource', function ($resource, config) {
+ return $resource(Config.service.url + 'models/:modelId/:propName/:propValue/:action', {}, {
+ list: {method: 'GET', params: {}, isArray: true},
+ drop: {method: 'DELETE', params: {}, isArray: false},
+ save: {method: 'POST', params: {}, isArray: false},
+ update: {method: 'PUT', params: {}, isArray: false},
+ });
+}]);
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/services/tree.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/tree.js b/webapp/app/js/services/tree.js
index 0a565af..d6f346f 100755
--- a/webapp/app/js/services/tree.js
+++ b/webapp/app/js/services/tree.js
@@ -22,15 +22,15 @@ KylinApp.service('CubeGraphService', function () {
width = 1100 - margin.right - margin.left,
height = 600;
- this.buildTree = function (cube) {
- $("#cube_graph_" + cube.name).empty();
+ this.buildTree = function (model) {
+ $("#model_graph_" + model.name).empty();
var tree = d3.layout.tree().size([height, width - 160]);
var diagonal = d3.svg.diagonal().projection(function (d) {
return [d.y, d.x];
});
- var svg = d3.select("#cube_graph_" + cube.name).append("svg:svg")
+ var svg = d3.select("#model_graph_" + model.name).append("svg:svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height)
.append("svg:g")
@@ -38,14 +38,13 @@ KylinApp.service('CubeGraphService', function () {
var graphData = {
"type": "fact",
- "name": cube.model.fact_table,
+ "name": model.fact_table,
"children": []
};
- cube.graph = (!!cube.graph) ? cube.graph : {};
+ model.graph = (!!model.graph) ? model.graph : {};
- //angular.forEach(cube.detail.dimensions, function (dimension, index) {
- angular.forEach(cube.model.lookups, function (lookup, index) {
+ angular.forEach(model.lookups, function (lookup, index) {
if (lookup.join && lookup.join.primary_key.length > 0) {
var dimensionNode;
@@ -76,9 +75,9 @@ KylinApp.service('CubeGraphService', function () {
}
});
- angular.forEach(cube.detail.dimensions, function (dimension, index) {
+ angular.forEach(model.dimensions, function (dimension, index) {
// for dimension on lookup table
- if(cube.model.fact_table!==dimension.table){
+ if(model.fact_table!==dimension.table){
var lookup = _.find(graphData.children,function(item){
return item.name === dimension.table;
});
@@ -130,28 +129,28 @@ KylinApp.service('CubeGraphService', function () {
};
});
- cube.graph.columnsCount = 0;
- cube.graph.tree = tree;
- cube.graph.root = graphData;
- cube.graph.svg = svg;
- cube.graph.diagonal = diagonal;
- cube.graph.i = 0;
-
- cube.graph.root.x0 = height / 2;
- cube.graph.root.y0 = 0;
- update(cube.graph.root, cube);
+ model.graph.columnsCount = 0;
+ model.graph.tree = tree;
+ model.graph.root = graphData;
+ model.graph.svg = svg;
+ model.graph.diagonal = diagonal;
+ model.graph.i = 0;
+
+ model.graph.root.x0 = height / 2;
+ model.graph.root.y0 = 0;
+ update(model.graph.root, model);
}
- function update(source, cube) {
+ function update(source, model) {
var duration = 750;
// Compute the new tree layout.
- var nodes = cube.graph.tree.nodes(cube.graph.root).reverse();
+ var nodes = model.graph.tree.nodes(model.graph.root).reverse();
// Update the nodes
- var node = cube.graph.svg.selectAll("g.node")
+ var node = model.graph.svg.selectAll("g.node")
.data(nodes, function (d) {
- return d.id || (d.id = ++cube.graph.i);
+ return d.id || (d.id = ++model.graph.i);
});
var nodeEnter = node.enter().append("svg:g")
@@ -181,22 +180,22 @@ KylinApp.service('CubeGraphService', function () {
d.children = null;
if (d.type == 'dimension') {
- cube.graph.columnsCount -= d._children.length;
+ model.graph.columnsCount -= d._children.length;
}
} else {
d.children = d._children;
d._children = null;
if (d.type == 'dimension') {
- cube.graph.columnsCount += d.children.length;
+ model.graph.columnsCount += d.children.length;
}
}
var perColumn = 35;
- var newHeight = (((cube.graph.columnsCount * perColumn > height) ? cube.graph.columnsCount * perColumn : height));
- $("#cube_graph_" + cube.name + " svg").height(newHeight);
- cube.graph.tree.size([newHeight, width - 160]);
- update(d, cube);
+ var newHeight = (((model.graph.columnsCount * perColumn > height) ? model.graph.columnsCount * perColumn : height));
+ $("#model_graph_" + model.name + " svg").height(newHeight);
+ model.graph.tree.size([newHeight, width - 160]);
+ update(d, model);
});
nodeEnter.append("svg:text")
@@ -210,7 +209,7 @@ KylinApp.service('CubeGraphService', function () {
var joinTip = "";
angular.forEach(d.join.primary_key, function (pk, index) {
- joinTip += ( cube.graph.root.name + "." + d.join.foreign_key[index] + " = " + d.name + "." + pk + "<br>");
+ joinTip += ( model.graph.root.name + "." + d.join.foreign_key[index] + " = " + d.name + "." + pk + "<br>");
});
d.tooltip = d3.select("body")
@@ -286,8 +285,8 @@ KylinApp.service('CubeGraphService', function () {
.remove();
// Update the links…
- var link = cube.graph.svg.selectAll("path.link")
- .data(cube.graph.tree.links(nodes), function (d) {
+ var link = model.graph.svg.selectAll("path.link")
+ .data(model.graph.tree.links(nodes), function (d) {
return d.target.id;
});
@@ -296,23 +295,23 @@ KylinApp.service('CubeGraphService', function () {
.attr("class", "link")
.attr("d", function (d) {
var o = {x: source.x0, y: source.y0};
- return cube.graph.diagonal({source: o, target: o});
+ return model.graph.diagonal({source: o, target: o});
})
.transition()
.duration(duration)
- .attr("d", cube.graph.diagonal);
+ .attr("d", model.graph.diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
- .attr("d", cube.graph.diagonal);
+ .attr("d", model.graph.diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {x: source.x, y: source.y};
- return cube.graph.diagonal({source: o, target: o});
+ return model.graph.diagonal({source: o, target: o});
})
.remove();
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/js/services/users.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/users.js b/webapp/app/js/services/users.js
index 7308a98..55c1508 100644
--- a/webapp/app/js/services/users.js
+++ b/webapp/app/js/services/users.js
@@ -18,9 +18,9 @@
KylinApp.service('UserService', function ($http, $q) {
var roles = {
- 'ROLE_MODELER': '/cubes',
- 'ROLE_ANALYST': '/cubes',
- 'ROLE_ADMIN': '/cubes'
+ 'ROLE_MODELER': '/models',
+ 'ROLE_ANALYST': '/models',
+ 'ROLE_ADMIN': '/models'
};
var curUser = {};
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/less/app.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/app.less b/webapp/app/less/app.less
index f60a698..7296eb9 100644
--- a/webapp/app/less/app.less
+++ b/webapp/app/less/app.less
@@ -213,6 +213,10 @@ table .radio {
.cube-detail {
background-color: white;
}
+.model-detail {
+ background-color: white;
+}
+
/* Query content */
.query-content {
@@ -316,7 +320,7 @@ pre {
}
//cube graph
-.cube_graph {
+.model_graph {
svg {
width: auto;
height: auto;
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/partials/cubeDesigner/data_model.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/data_model.html b/webapp/app/partials/cubeDesigner/data_model.html
deleted file mode 100644
index 4aeb1da..0000000
--- a/webapp/app/partials/cubeDesigner/data_model.html
+++ /dev/null
@@ -1,199 +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.
--->
-
-<div ng-controller="CubeModelCtrl">
- <ng-form name="model_form">
-
- <!-- Fact Table Name -->
- <div class="form-group">
- <div class="row">
- <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">
- <typeahead ng-if="state.mode=='edit'" items="tableModel.selectProjectTables" prompt="Fact Table Name"
- title="name" model="metaModel.model.fact_table" required="true"></typeahead>
- <span ng-if="state.mode=='view'">{{metaModel.model.fact_table}}</span>
- </div>
- </div>
- </div>
-
- <!-- Lookup Tables Summary -->
- <div class="dataTables_wrapper form-inline no-footer">
- <div class="row">
- <div class="col-xs-6" ng-if="state.mode=='edit'">
- <button type="button" class="btn btn-primary" ng-disabled="!metaModel.model.fact_table.length"
- ng-click="openLookupModal()">
- <i class="fa fa-plus"></i> Add Lookup Table
- </button>
- </div>
- <div class="col-xs-6" ng-if="state.mode!='edit'">
- <b>{{metaModel.model.lookups.length ? 'Lookup Tables' : 'No Lookup Tables'}}</b>
- </div>
- <div class="col-xs-6">
- <span class="pull-right input-icon input-icon-right nav-search" style="margin-left: 22px;" ng-if="metaModel.model.lookups.length">
- <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="lookupState.filter"/>
- <i class="ace-icon fa fa-search nav-search-icon"></i>
- </span>
- </div>
- </div>
- <table class="table table-striped table-hover" ng-if="metaModel.model.lookups.length">
- <thead>
- <tr>
- <th>ID</th>
- <th>Table Name</th>
- <th>Join Type</th>
- <th>Join Condition</th>
- <th ng-if="state.mode=='edit'">Actions</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="lookup in metaModel.model.lookups | filter:lookupState.filter track by $index">
- <td>
- <b>{{$index + 1}}</b>
- </td>
- <!-- Table Name -->
- <td>
- <span tooltip="Lookup Table Name">{{lookup.table}}</span>
- </td>
- <!-- Join Type -->
- <td>
- <span>{{lookup.join.type}}</span>
- </td>
- <!-- Join Condition -->
- <td>
- <ul class="list-unstyled">
- <li ng-repeat="pk in lookup.join.primary_key track by $index">
- <code>{{lookup.table + '.' + pk}} = {{metaModel.model.fact_table + '.' + lookup.join.foreign_key[$index]}}</code>
- </li>
- </ul>
- </td>
- <td ng-if="state.mode=='edit'">
- <!-- edit button -->
- <button class="btn btn-xs btn-info" ng-disabled="lookupState.editing"
- ng-click="editLookup(lookup)" tooltip="Edit Lookup"><i class="fa fa-pencil"></i>
- </button>
- <!-- remove button -->
- <button class="btn btn-xs btn-danger" ng-disabled="lookupState.editing"
- ng-click="removeLookup(lookup)" tooltip="Remove Lookup"><i class="fa fa-trash-o"></i>
- </button>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </ng-form>
-
- <!-- Add Lookup Table Form -->
- <script type="text/ng-template" id="dataModelLookupTable.html">
- <div class="modal-header">
- <h4 class="box-title lighter">{{lookupState.editing ? 'Edit' : 'Add'}} Lookup</h4>
- </div>
- <div class="modal-body">
- <div class="row">
- <div class="col-xs-8">
- <ng-form name="lookup_form">
- <!--Table Name-->
- <div class="form-group">
- <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>
- </div>
- </div>
- </div>
-
- <!--Join Type and Columns-->
- <div class="form-group">
- <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"
- ng-options="joinType.value as joinType.name for joinType in cubeConfig.joinTypes">
- <option value=""></option>
- </select>
- </div>
- </div>
- </div>
- <div class="form-group">
- <div class="row">
- <div class="col-xs-9">
- <div ng-repeat="joinIndex in [] | range: newLookup.join.primary_key.length">
- <div>
- <select style="width: 45%" chosen data-placeholder="Lookup Table Column"
- ng-model="newLookup.join.primary_key[$index]"
- ng-options="columns.name as columns.name for columns in getColumnsByTable(newLookup.table)" >
- <option value=""></option>
- </select>
- <b>=</b>
- <select style="width: 45%" chosen data-placeholder="Fact Table Column"
- ng-model="newLookup.join.foreign_key[$index]"
- ng-options="columns.name as columns.name for columns in getColumnsByTable(metaModel.model.fact_table)" >
- <option value=""></option>
- </select>
- <button class="pull-right btn btn-xs btn-danger" style="cursor: pointer" tooltip="Delete"
- ng-click="removeJoin($index);">
- <i class="fa fa-trash-o pointer"></i>
- </button>
- </div>
- <div class="space-4"></div>
- </div>
- </div>
- </div>
- </div>
- <div class="form-group">
- <div class="row">
- <div class="col-sm-3">
- <button class="btn btn-xs btn-info"
- ng-if="newLookup.join.type"
- ng-click="addNewJoin();">
- <i class="fa fa-plus"></i> New Join Condition</button>
- </div>
- </div>
- </div>
-
- </ng-form>
- </div>
-
- <!--Tips-->
- <div class="col-xs-4">
- <div class="box box-solid">
- <div class="box-header">
- <h4 class="box-title">Tips</h4>
- </div>
- <div class="box-body">
- <div class="row">
- <div class="col-xs-12">
- <ol class="text-info">
- <li>Pick up lookup table at first</li>
- <li>Specify join relationship between chosen lookup table and fact table</li>
- <li>Join Type have to be same as will be used in query</li>
- </ol>
- </div>
- </div>
- </div>
- </div>
- </div>
- </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-warning" ng-click="cancel()">Cancel</button>
- </div>
- </script>
-</div>
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/partials/header.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/header.html b/webapp/app/partials/header.html
index 18a9b66..9a55034 100644
--- a/webapp/app/partials/header.html
+++ b/webapp/app/partials/header.html
@@ -43,8 +43,8 @@
<li class="{{activeTab=='query'?'purple':'green'}}" ng-if="userService.isAuthorized()">
<a href="query">Insight</a>
</li>
- <li class="{{activeTab=='cubes'?'purple':'green'}}" ng-if="userService.isAuthorized()">
- <a href="cubes">Model</a>
+ <li class="{{activeTab=='models'?'purple':'green'}}" ng-if="userService.isAuthorized()">
+ <a href="models">Model</a>
</li>
<li class="{{activeTab=='jobs'?'purple':'green'}}" ng-if="userService.isAuthorized()">
<a href="jobs">Monitor</a>
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/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
new file mode 100644
index 0000000..c8cc5a7
--- /dev/null
+++ b/webapp/app/partials/modelDesigner/data_model.html
@@ -0,0 +1,199 @@
+<!--
+* 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.
+-->
+
+<div ng-controller="CubeModelCtrl">
+ <ng-form name="model_form">
+
+ <!-- Fact Table Name -->
+ <div class="form-group">
+ <div class="row">
+ <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">
+ <typeahead ng-if="state.mode=='edit'" items="tableModel.selectProjectTables" prompt="Fact Table Name"
+ title="name" model="model.fact_table" required="true"></typeahead>
+ <span ng-if="state.mode=='view'">{{model.fact_table}}</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- Lookup Tables Summary -->
+ <div class="dataTables_wrapper form-inline no-footer">
+ <div class="row">
+ <div class="col-xs-6" ng-if="state.mode=='edit'">
+ <button type="button" class="btn btn-primary" ng-disabled="!model.fact_table.length"
+ ng-click="openLookupModal()">
+ <i class="fa fa-plus"></i> Add Lookup Table
+ </button>
+ </div>
+ <div class="col-xs-6" ng-if="state.mode!='edit'">
+ <b>{{model.lookups.length ? 'Lookup Tables' : 'No Lookup Tables'}}</b>
+ </div>
+ <div class="col-xs-6">
+ <span class="pull-right input-icon input-icon-right nav-search" style="margin-left: 22px;" ng-if="model.lookups.length">
+ <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="lookupState.filter"/>
+ <i class="ace-icon fa fa-search nav-search-icon"></i>
+ </span>
+ </div>
+ </div>
+ <table class="table table-striped table-hover" ng-if="model.lookups.length">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Table Name</th>
+ <th>Join Type</th>
+ <th>Join Condition</th>
+ <th ng-if="state.mode=='edit'">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="lookup in model.lookups | filter:lookupState.filter track by $index">
+ <td>
+ <b>{{$index + 1}}</b>
+ </td>
+ <!-- Table Name -->
+ <td>
+ <span tooltip="Lookup Table Name">{{lookup.table}}</span>
+ </td>
+ <!-- Join Type -->
+ <td>
+ <span>{{lookup.join.type}}</span>
+ </td>
+ <!-- Join Condition -->
+ <td>
+ <ul class="list-unstyled">
+ <li ng-repeat="pk in lookup.join.primary_key track by $index">
+ <code>{{lookup.table + '.' + pk}} = {{model.fact_table + '.' + lookup.join.foreign_key[$index]}}</code>
+ </li>
+ </ul>
+ </td>
+ <td ng-if="state.mode=='edit'">
+ <!-- edit button -->
+ <button class="btn btn-xs btn-info" ng-disabled="lookupState.editing"
+ ng-click="editLookup(lookup)" tooltip="Edit Lookup"><i class="fa fa-pencil"></i>
+ </button>
+ <!-- remove button -->
+ <button class="btn btn-xs btn-danger" ng-disabled="lookupState.editing"
+ ng-click="removeLookup(lookup)" tooltip="Remove Lookup"><i class="fa fa-trash-o"></i>
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </ng-form>
+
+ <!-- Add Lookup Table Form -->
+ <script type="text/ng-template" id="dataModelLookupTable.html">
+ <div class="modal-header">
+ <h4 class="box-title lighter">{{lookupState.editing ? 'Edit' : 'Add'}} Lookup</h4>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-xs-8">
+ <ng-form name="lookup_form">
+ <!--Table Name-->
+ <div class="form-group">
+ <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>
+ </div>
+ </div>
+ </div>
+
+ <!--Join Type and Columns-->
+ <div class="form-group">
+ <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"
+ ng-options="joinType.value as joinType.name for joinType in cubeConfig.joinTypes">
+ <option value=""></option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="row">
+ <div class="col-xs-9">
+ <div ng-repeat="joinIndex in [] | range: newLookup.join.primary_key.length">
+ <div>
+ <select style="width: 45%" chosen data-placeholder="Lookup Table Column"
+ ng-model="newLookup.join.primary_key[$index]"
+ ng-options="columns.name as columns.name for columns in getColumnsByTable(newLookup.table)" >
+ <option value=""></option>
+ </select>
+ <b>=</b>
+ <select style="width: 45%" chosen data-placeholder="Fact Table Column"
+ ng-model="newLookup.join.foreign_key[$index]"
+ ng-options="columns.name as columns.name for columns in getColumnsByTable(model.fact_table)" >
+ <option value=""></option>
+ </select>
+ <button class="pull-right btn btn-xs btn-danger" style="cursor: pointer" tooltip="Delete"
+ ng-click="removeJoin($index);">
+ <i class="fa fa-trash-o pointer"></i>
+ </button>
+ </div>
+ <div class="space-4"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="row">
+ <div class="col-sm-3">
+ <button class="btn btn-xs btn-info"
+ ng-if="newLookup.join.type"
+ ng-click="addNewJoin();">
+ <i class="fa fa-plus"></i> New Join Condition</button>
+ </div>
+ </div>
+ </div>
+
+ </ng-form>
+ </div>
+
+ <!--Tips-->
+ <div class="col-xs-4">
+ <div class="box box-solid">
+ <div class="box-header">
+ <h4 class="box-title">Tips</h4>
+ </div>
+ <div class="box-body">
+ <div class="row">
+ <div class="col-xs-12">
+ <ol class="text-info">
+ <li>Pick up lookup table at first</li>
+ <li>Specify join relationship between chosen lookup table and fact table</li>
+ <li>Join Type have to be same as will be used in query</li>
+ </ol>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </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-warning" ng-click="cancel()">Cancel</button>
+ </div>
+ </script>
+</div>
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/7b526242/webapp/app/partials/modelDesigner/incremental.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/incremental.html b/webapp/app/partials/modelDesigner/incremental.html
new file mode 100644
index 0000000..3238b1c
--- /dev/null
+++ b/webapp/app/partials/modelDesigner/incremental.html
@@ -0,0 +1,94 @@
+<!--
+* 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.
+-->
+
+<div ng-controller="ModelRefreshCtrl">
+<div class="row">
+ <div class="col-xs-8">
+
+ <div class="form-group" ng-hide="true">
+ <div class="row">
+ <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Partition Type</b></label>
+ <div class="col-xs-12 col-sm-6">
+ <select class="form-control"
+ ng-if="state.mode=='edit'"
+ chosen ng-model="model.partition_desc.partition_type"
+ ng-options="ddt as ddt for ddt in cubeConfig.cubePartitionTypes">
+ <option value=""></option>
+ </select>
+ <span ng-if="state.mode=='view'">{{model.partition_desc.partition_type}}</span>
+ </div>
+ </div>
+ </div>
+
+ <!--Partition Column-->
+ <div class="form-group">
+ <div class="row">
+ <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Partition Date Column</b></label>
+ <div class="col-xs-12 col-sm-6">
+
+ <select style="width: 100%" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT"
+ ng-required="model.partition_desc.partition_date_start"
+ ng-model="model.partition_desc.partition_date_column"
+ ng-if="state.mode=='edit'"
+ data-placement=""
+ ng-options="model.fact_table+'.'+columns.name as model.fact_table+'.'+columns.name for columns in getPartitonColumns(model.fact_table)" >
+ <option value="">--Select Partition Column--</option>
+ </select>
+ <p class="text-red" ng-if="state.mode=='edit'">(data format in column should be 'YYYY-MM-DD')</p>
+ <span ng-if="state.mode=='view'">
+ {{!!(model.partition_desc.partition_date_column)?model.partition_desc.partition_date_column: ''}}</span>
+ </div>
+ </div>
+ </div>
+
+ <!--Data Range Start-->
+ <div class="form-group">
+ <div class="row">
+ <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Start Date</b></label>
+ <div class="col-xs-12 col-sm-6">
+ <!--edit model will convert in MetaModel.converDateToGMT-->
+ <input type="text" class="form-control" datepicker-popup="yyyy-MM-dd"
+ ng-model="model.partition_desc.partition_date_start" ng-if="state.mode=='edit'"
+ placeholder="Click to choose start date..." is-open="opened" />
+ <!--vier model will convert use filter-->
+ <span ng-if="state.mode=='view'&&model.partition_desc.partition_date_column">{{(model.partition_desc.partition_date_start)|reverseToGMT0 }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-xs-4">
+ <div class="box box-solid">
+ <div class="box-header">
+ <h4 class="box-title">Tips</h4>
+ </div>
+ <div class="box-body">
+ <div class="row">
+ <div class="col-xs-12">
+ <ol class="text-info">
+ <li>Not required,leave as default if cube always need full build</li>
+ <li>Partition column will select 'date' or 'string' type column from fact table</li>
+ <li>If column selected,please indicate start date to just pull certain data from source</li>
+ </ol>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+</div>