Repository: kylin Updated Branches: refs/heads/2.x-staging 3fb67ca78 -> 1ea781f00
minor, remove unused files Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/1ea781f0 Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/1ea781f0 Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/1ea781f0 Branch: refs/heads/2.x-staging Commit: 1ea781f0005c1e20c0e775e660e47a6964f07bcb Parents: 3fb67ca Author: lidongsjtu <lid...@apache.org> Authored: Wed Mar 2 17:34:59 2016 +0800 Committer: lidongsjtu <lid...@apache.org> Committed: Wed Mar 2 17:34:59 2016 +0800 ---------------------------------------------------------------------- ...port-load-hive-table-from-listed-tree-.patch | 864 ------------------- 1 file changed, 864 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/1ea781f0/0001-KYLIN-1074-support-load-hive-table-from-listed-tree-.patch ---------------------------------------------------------------------- diff --git a/0001-KYLIN-1074-support-load-hive-table-from-listed-tree-.patch b/0001-KYLIN-1074-support-load-hive-table-from-listed-tree-.patch deleted file mode 100644 index 31cc017..0000000 --- a/0001-KYLIN-1074-support-load-hive-table-from-listed-tree-.patch +++ /dev/null @@ -1,864 +0,0 @@ -From 1a79ef1aec557259f9611f5b3199c2e90400be77 Mon Sep 17 00:00:00 2001 -From: Jason <jiat...@163.com> -Date: Wed, 2 Mar 2016 14:40:19 +0800 -Subject: [PATCH] KYLIN-1074 support load hive table from listed tree, patch - from @nichunen - ---- - build/conf/kylin.properties | 2 + - examples/test_case_data/sandbox/kylin.properties | 1 + - pom.xml | 2 + - .../kylin/rest/controller/TableController.java | 44 +++ - .../org/apache/kylin/source/hive/HiveClient.java | 8 + - webapp/app/index.html | 1 + - webapp/app/js/controllers/sourceMeta.js | 186 ++++++++++- - webapp/app/js/directives/angular-tree-control.js | 363 +++++++++++++++++++++ - webapp/app/js/services/kylinProperties.js | 15 +- - webapp/app/js/services/tables.js | 7 +- - webapp/app/partials/tables/source_table_tree.html | 26 ++ - webapp/bower.json | 3 +- - webapp/grunt.json | 1 - - 13 files changed, 649 insertions(+), 10 deletions(-) - create mode 100644 webapp/app/js/directives/angular-tree-control.js - -diff --git a/build/conf/kylin.properties b/build/conf/kylin.properties -index a4b8c3b..e8add7c 100644 ---- a/build/conf/kylin.properties -+++ b/build/conf/kylin.properties -@@ -158,3 +158,5 @@ deploy.env=DEV - - ###########################deprecated configs####################### - kylin.sandbox=true -+ -+kylin.web.hive.limit=20 -\ No newline at end of file -diff --git a/examples/test_case_data/sandbox/kylin.properties b/examples/test_case_data/sandbox/kylin.properties -index 9451b78..1a74b80 100644 ---- a/examples/test_case_data/sandbox/kylin.properties -+++ b/examples/test_case_data/sandbox/kylin.properties -@@ -131,3 +131,4 @@ kylin.web.contact_mail= - deploy.env=DEV - - -+kylin.web.hive.limit=20 -\ No newline at end of file -diff --git a/pom.xml b/pom.xml -index 9d9a54b..537693f 100644 ---- a/pom.xml -+++ b/pom.xml -@@ -774,6 +774,8 @@ - <!-- MIT license --> - <exclude>webapp/app/css/AdminLTE.css</exclude> - <exclude>webapp/app/js/directives/kylin_abn_tree_directive.js</exclude> -+ <exclude>webapp/app/js/directives/angular-tree-control.js</exclude> -+ - - <!--configuration file --> - <exclude>webapp/app/routes.json</exclude> -diff --git a/server/src/main/java/org/apache/kylin/rest/controller/TableController.java b/server/src/main/java/org/apache/kylin/rest/controller/TableController.java -index 39af7db..ea5fdd4 100644 ---- a/server/src/main/java/org/apache/kylin/rest/controller/TableController.java -+++ b/server/src/main/java/org/apache/kylin/rest/controller/TableController.java -@@ -33,6 +33,7 @@ import org.apache.kylin.rest.request.CardinalityRequest; - import org.apache.kylin.rest.request.StreamingRequest; - import org.apache.kylin.rest.response.TableDescResponse; - import org.apache.kylin.rest.service.CubeService; -+import org.apache.kylin.source.hive.HiveClient; - import org.slf4j.Logger; - import org.slf4j.LoggerFactory; - import org.springframework.beans.factory.annotation.Autowired; -@@ -205,6 +206,49 @@ public class TableController extends BasicController { - return descs; - } - -+ /** -+ * Show all databases in Hive -+ * -+ * @return Hive databases list -+ * @throws IOException -+ */ -+ @RequestMapping(value = "/hive", method = { RequestMethod.GET }) -+ @ResponseBody -+ private static List<String> showHiveDatabases() throws IOException { -+ HiveClient hiveClient = new HiveClient(); -+ List<String> results = null; -+ -+ try { -+ results = hiveClient.getHiveDbNames(); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ throw new IOException(e); -+ } -+ return results; -+ } -+ -+ /** -+ * Show all tables in a Hive database -+ * -+ * @return Hive table list -+ * @throws IOException -+ */ -+ @RequestMapping(value = "/hive/{database}", method = { RequestMethod.GET }) -+ @ResponseBody -+ private static List<String> showHiveTables(@PathVariable String database) throws IOException { -+ HiveClient hiveClient = new HiveClient(); -+ List<String> results = null; -+ -+ try { -+ results = hiveClient.getHiveTableNames(database); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ throw new IOException(e); -+ } -+ return results; -+ } -+ -+ - public void setCubeService(CubeService cubeService) { - this.cubeMgmtService = cubeService; - } -diff --git a/source-hive/src/main/java/org/apache/kylin/source/hive/HiveClient.java b/source-hive/src/main/java/org/apache/kylin/source/hive/HiveClient.java -index 178889e..a99b304 100644 ---- a/source-hive/src/main/java/org/apache/kylin/source/hive/HiveClient.java -+++ b/source-hive/src/main/java/org/apache/kylin/source/hive/HiveClient.java -@@ -132,6 +132,14 @@ public class HiveClient { - return getBasicStatForTable(new org.apache.hadoop.hive.ql.metadata.Table(table), StatsSetupConst.NUM_FILES); - } - -+ public List<String> getHiveDbNames() throws Exception { -+ return getMetaStoreClient().getAllDatabases(); -+ } -+ -+ public List<String> getHiveTableNames(String database) throws Exception { -+ return getMetaStoreClient().getAllTables(database); -+ } -+ - /** - * COPIED FROM org.apache.hadoop.hive.ql.stats.StatsUtil for backward compatibility - * -diff --git a/webapp/app/index.html b/webapp/app/index.html -index 11ca283..b4eb9d7 100644 ---- a/webapp/app/index.html -+++ b/webapp/app/index.html -@@ -113,6 +113,7 @@ - <script src="js/filters/filter.js"></script> - <script src="js/directives/directives.js"></script> - <script src="js/directives/kylin_abn_tree_directive.js"></script> -+<script src="js/directives/angular-tree-control.js"></script> - <script src="js/factories/graph.js"></script> - <script src="js/services/cache.js"></script> - <script src="js/services/message.js"></script> -diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js -index abdeeb8..c87d6ef 100755 ---- a/webapp/app/js/controllers/sourceMeta.js -+++ b/webapp/app/js/controllers/sourceMeta.js -@@ -19,14 +19,14 @@ - 'use strict'; - - KylinApp -- .controller('SourceMetaCtrl', function ($scope, $cacheFactory, $q, $window, $routeParams, CubeService, $modal, TableService, $route, loadingRequest, SweetAlert, tableConfig, TableModel,cubeConfig) { -+ .controller('SourceMetaCtrl', function ($scope, $cacheFactory, $q, $window, $routeParams, CubeService, $modal, TableService, $route, loadingRequest, SweetAlert, tableConfig, TableModel,cubeConfig,kylinConfig) { - var $httpDefaultCache = $cacheFactory.get('$http'); - $scope.tableModel = TableModel; - $scope.tableModel.selectedSrcDb = []; - $scope.tableModel.selectedSrcTable = {}; - $scope.window = 0.68 * $window.innerHeight; - $scope.tableConfig = tableConfig; -- -+ $scope.kylinConfig = kylinConfig; - - $scope.state = { - filterAttr: 'id', filterReverse: false, reverseColumn: 'id', -@@ -100,13 +100,193 @@ KylinApp - }); - }; - -- var ModalInstanceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope) { -+ $scope.openTreeModal = function () { -+ $modal.open({ -+ templateUrl: 'addHiveTableFromTree.html', -+ controller: ModalInstanceCtrl, -+ resolve: { -+ tableNames: function () { -+ return $scope.tableNames; -+ }, -+ projectName:function(){ -+ return $scope.projectModel.selectedProject; -+ }, -+ scope: function () { -+ return $scope; -+ } -+ } -+ }); -+ }; -+ -+ var ModalInstanceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope,kylinConfig) { - $scope.tableNames = ""; - $scope.projectName = projectName; - $scope.cancel = function () { - $modalInstance.dismiss('cancel'); - }; -+ -+ $scope.kylinConfig = kylinConfig; -+ -+ -+ $scope.treeOptions = {multiSelection: true}; -+ $scope.selectedNodes = []; -+ $scope.hiveLimit = kylinConfig.getHiveLimit(); -+ -+ $scope.loadHive = function () { -+ if($scope.hiveLoaded) -+ return; -+ TableService.showHiveDatabases({}, function (databases) { -+ $scope.dbNum = databases.length; -+ if (databases.length > 0) { -+ $scope.hiveMap = {}; -+ for (var i = 0; i < databases.length; i++) { -+ var dbName = databases[i]; -+ var hiveData = {"dbname":dbName,"tables":[],"expanded":false}; -+ $scope.hive.push(hiveData); -+ $scope.hiveMap[dbName] = i; -+ } -+ } -+ $scope.hiveLoaded = true; -+ $scope.showMoreDatabases(); -+ }); -+ } -+ -+ $scope.showMoreTables = function(hiveTables, node){ -+ var shownTimes = parseInt(node.children.length / $scope.hiveLimit); -+ var from = $scope.hiveLimit * shownTimes; -+ var to = 0; -+ var hasMore = false; -+ if(from + $scope.hiveLimit > hiveTables.length) { -+ to = hiveTables.length - 1; -+ } else { -+ to = from + $scope.hiveLimit - 1; -+ hasMore = true; -+ } -+ if(!angular.isUndefined(node.children[from])){ -+ node.children.pop(); -+ } -+ -+ for(var idx = from; idx <= to; idx++){ -+ node.children.push({"label":node.label+'.'+hiveTables[idx],"id":idx-from+1,"children":[]}); -+ } -+ -+ if(hasMore){ -+ var loading = {"label":"","id":65535,"children":[]}; -+ node.children.push(loading); -+ } -+ } -+ -+ $scope.showAllTables = function(hiveTables, node){ -+ var shownTimes = parseInt(node.children.length / $scope.hiveLimit); -+ var from = $scope.hiveLimit * shownTimes; -+ var to = hiveTables.length - 1; -+ if(!angular.isUndefined(node.children[from])){ -+ node.children.pop(); -+ } -+ for(var idx = from; idx <= to; idx++){ -+ node.children.push({"label":node.label+'.'+hiveTables[idx],"id":idx-from+1,"children":[]}); -+ } -+ } -+ -+ $scope.showMoreDatabases = function(){ -+ var shownTimes = parseInt($scope.treedata.length / $scope.hiveLimit); -+ var from = $scope.hiveLimit * shownTimes; -+ var to = 0; -+ var hasMore = false; -+ if(from + $scope.hiveLimit > $scope.hive.length) { -+ to = $scope.hive.length - 1; -+ } else { -+ to = from + $scope.hiveLimit - 1; -+ hasMore = true; -+ } -+ if(!angular.isUndefined($scope.treedata[from])){ -+ $scope.treedata.pop(); -+ } -+ -+ for(var idx = from; idx <= to; idx++){ -+ var children = []; -+ var loading = {"label":"","id":0,"children":[]}; -+ children.push(loading); -+ $scope.treedata.push({"label":$scope.hive[idx].dbname,"id":idx+1,"children":children,"expanded":false}); -+ } -+ -+ if(hasMore){ -+ var loading = {"label":"","id":65535,"children":[0]}; -+ $scope.treedata.push(loading); -+ } -+ } -+ -+ $scope.showAllDatabases = function(){ -+ var shownTimes = parseInt($scope.treedata.length / $scope.hiveLimit); -+ var from = $scope.hiveLimit * shownTimes; -+ var to = $scope.hive.length - 1; -+ -+ if(!angular.isUndefined($scope.treedata[from])){ -+ $scope.treedata.pop(); -+ } -+ -+ for(var idx = from; idx <= to; idx++){ -+ var children = []; -+ var loading = {"label":"","id":0,"children":[]}; -+ children.push(loading); -+ $scope.treedata.push({"label":$scope.hive[idx].dbname,"id":idx+1,"children":children,"expanded":false}); -+ } -+ } -+ -+ $scope.showMoreClicked = function($parentNode){ -+ if($parentNode == null){ -+ $scope.showMoreDatabases(); -+ } else { -+ $scope.showMoreTables($scope.hive[$scope.hiveMap[$parentNode.label]].tables,$parentNode); -+ } -+ } -+ -+ $scope.showAllClicked = function($parentNode){ -+ if($parentNode == null){ -+ $scope.showAllDatabases(); -+ } else { -+ $scope.showAllTables($scope.hive[$scope.hiveMap[$parentNode.label]].tables,$parentNode); -+ } -+ } -+ -+ $scope.showToggle = function(node) { -+ if(node.expanded == false){ -+ TableService.showHiveTables({"database": node.label},function (hive_tables){ -+ var tables = []; -+ for (var i = 0; i < hive_tables.length; i++) { -+ tables.push(hive_tables[i]); -+ } -+ $scope.hive[$scope.hiveMap[node.label]].tables = tables; -+ $scope.showMoreTables(tables,node); -+ node.expanded = true; -+ }); -+ } -+ } -+ -+ $scope.showSelected = function(node) { -+ -+ } -+ -+ if(angular.isUndefined($scope.hive) || angular.isUndefined($scope.hiveLoaded) || angular.isUndefined($scope.treedata) ){ -+ $scope.hive = []; -+ $scope.hiveLoaded = false; -+ $scope.treedata = []; -+ $scope.loadHive(); -+ } -+ -+ -+ -+ - $scope.add = function () { -+ -+ if($scope.tableNames.length === 0 && $scope.selectedNodes.length > 0) { -+ for(var i = 0; i < $scope.selectedNodes.length; i++){ -+ if($scope.selectedNodes[i].label.indexOf(".") >= 0){ -+ $scope.tableNames += ($scope.selectedNodes[i].label) += ','; -+ } -+ } -+ } -+ - if ($scope.tableNames.trim() === "") { - SweetAlert.swal('', 'Please input table(s) you want to synchronize.', 'info'); - return; -diff --git a/webapp/app/js/directives/angular-tree-control.js b/webapp/app/js/directives/angular-tree-control.js -new file mode 100644 -index 0000000..6fca987 ---- /dev/null -+++ b/webapp/app/js/directives/angular-tree-control.js -@@ -0,0 +1,363 @@ -+/* -+ * The MIT License (MIT) -+ * -+ * Copyright (c) 2013 Steve -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy of -+ * this software and associated documentation files (the "Software"), to deal in -+ * the Software without restriction, including without limitation the rights to -+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -+ * the Software, and to permit persons to whom the Software is furnished to do so, -+ * subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in all -+ * copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -+ */ -+ -+(function ( angular ) { -+ 'use strict'; -+ -+ angular.module( 'treeControl', [] ) -+ .directive( 'treecontrol', ['$compile', function( $compile ) { -+ /** -+ * @param cssClass - the css class -+ * @param addClassProperty - should we wrap the class name with class="" -+ */ -+ function classIfDefined(cssClass, addClassProperty) { -+ if (cssClass) { -+ if (addClassProperty) -+ return 'class="' + cssClass + '"'; -+ else -+ return cssClass; -+ } -+ else -+ return ""; -+ } -+ -+ function ensureDefault(obj, prop, value) { -+ if (!obj.hasOwnProperty(prop)) -+ obj[prop] = value; -+ } -+ -+ return { -+ restrict: 'EA', -+ require: "treecontrol", -+ transclude: true, -+ scope: { -+ treeModel: "=", -+ selectedNode: "=?", -+ selectedNodes: "=?", -+ expandedNodes: "=?", -+ onSelection: "&", -+ onNodeToggle: "&", -+ options: "=?", -+ orderBy: "@", -+ reverseOrder: "@", -+ filterExpression: "=?", -+ filterComparator: "=?", -+ onDblclick: "&" -+ }, -+ controller: ['$scope', function( $scope ) { -+ -+ function defaultIsLeaf(node) { -+ return !node[$scope.options.nodeChildren] || node[$scope.options.nodeChildren].length === 0; -+ } -+ -+ function shallowCopy(src, dst) { -+ if (angular.isArray(src)) { -+ dst = dst || []; -+ -+ for ( var i = 0; i < src.length; i++) { -+ dst[i] = src[i]; -+ } -+ } else if (angular.isObject(src)) { -+ dst = dst || {}; -+ -+ for (var key in src) { -+ if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { -+ dst[key] = src[key]; -+ } -+ } -+ } -+ -+ return dst || src; -+ } -+ function defaultEquality(a, b) { -+ if (a === undefined || b === undefined) -+ return false; -+ a = shallowCopy(a); -+ a[$scope.options.nodeChildren] = []; -+ b = shallowCopy(b); -+ b[$scope.options.nodeChildren] = []; -+ return angular.equals(a, b); -+ } -+ -+ $scope.options = $scope.options || {}; -+ ensureDefault($scope.options, "multiSelection", false); -+ ensureDefault($scope.options, "nodeChildren", "children"); -+ ensureDefault($scope.options, "dirSelectable", "true"); -+ ensureDefault($scope.options, "injectClasses", {}); -+ ensureDefault($scope.options.injectClasses, "ul", ""); -+ ensureDefault($scope.options.injectClasses, "li", ""); -+ ensureDefault($scope.options.injectClasses, "liSelected", ""); -+ ensureDefault($scope.options.injectClasses, "iExpanded", ""); -+ ensureDefault($scope.options.injectClasses, "iCollapsed", ""); -+ ensureDefault($scope.options.injectClasses, "iLeaf", ""); -+ ensureDefault($scope.options.injectClasses, "label", ""); -+ ensureDefault($scope.options.injectClasses, "labelSelected", ""); -+ ensureDefault($scope.options, "equality", defaultEquality); -+ ensureDefault($scope.options, "isLeaf", defaultIsLeaf); -+ -+ $scope.selectedNodes = $scope.selectedNodes || []; -+ $scope.expandedNodes = $scope.expandedNodes || []; -+ $scope.expandedNodesMap = {}; -+ for (var i=0; i < $scope.expandedNodes.length; i++) { -+ $scope.expandedNodesMap[""+i] = $scope.expandedNodes[i]; -+ } -+ $scope.parentScopeOfTree = $scope.$parent; -+ -+ -+ function isSelectedNode(node) { -+ if (!$scope.options.multiSelection && ($scope.options.equality(node, $scope.selectedNode))) -+ return true; -+ else if ($scope.options.multiSelection && $scope.selectedNodes) { -+ for (var i = 0; (i < $scope.selectedNodes.length); i++) { -+ if ($scope.options.equality(node, $scope.selectedNodes[i])) { -+ return true; -+ } -+ } -+ return false; -+ } -+ } -+ -+ $scope.headClass = function(node) { -+ var liSelectionClass = classIfDefined($scope.options.injectClasses.liSelected, false); -+ var injectSelectionClass = ""; -+ if (liSelectionClass && isSelectedNode(node)) -+ injectSelectionClass = " " + liSelectionClass; -+ if ($scope.options.isLeaf(node)) -+ return "tree-leaf" + injectSelectionClass; -+ if ($scope.expandedNodesMap[this.$id]) -+ return "tree-expanded" + injectSelectionClass; -+ else -+ return "tree-collapsed" + injectSelectionClass; -+ }; -+ -+ $scope.iBranchClass = function() { -+ if ($scope.expandedNodesMap[this.$id]) -+ return classIfDefined($scope.options.injectClasses.iExpanded); -+ else -+ return classIfDefined($scope.options.injectClasses.iCollapsed); -+ }; -+ -+ $scope.nodeExpanded = function() { -+ return !!$scope.expandedNodesMap[this.$id]; -+ }; -+ -+ $scope.selectNodeHead = function() { -+ var expanding = $scope.expandedNodesMap[this.$id] === undefined; -+ $scope.expandedNodesMap[this.$id] = (expanding ? this.node : undefined); -+ if (expanding) { -+ $scope.expandedNodes.push(this.node); -+ } -+ else { -+ var index; -+ for (var i=0; (i < $scope.expandedNodes.length) && !index; i++) { -+ if ($scope.options.equality($scope.expandedNodes[i], this.node)) { -+ index = i; -+ } -+ } -+ if (index != undefined) -+ $scope.expandedNodes.splice(index, 1); -+ } -+ if ($scope.onNodeToggle) -+ $scope.onNodeToggle({node: this.node, expanded: expanding}); -+ }; -+ -+ $scope.selectNodeLabel = function( selectedNode ){ -+ if(selectedNode[$scope.options.nodeChildren] && selectedNode[$scope.options.nodeChildren].length > 0){ -+ this.selectNodeHead(); -+ } -+ if($scope.options.dirSelectable || !(selectedNode[$scope.options.nodeChildren] && selectedNode[$scope.options.nodeChildren].length > 0) ) -+ { -+ var selected = false; -+ if ($scope.options.multiSelection) { -+ var pos = $scope.selectedNodes.indexOf(selectedNode); -+ if (pos === -1) { -+ $scope.selectedNodes.push(selectedNode); -+ selected = true; -+ } else { -+ $scope.selectedNodes.splice(pos, 1); -+ } -+ } else { -+ if ($scope.selectedNode != selectedNode) { -+ $scope.selectedNode = selectedNode; -+ selected = true; -+ } -+ else { -+ $scope.selectedNode = undefined; -+ } -+ } -+ if ($scope.onSelection) -+ $scope.onSelection({node: selectedNode, selected: selected}); -+ } -+ }; -+ -+ -+ $scope.dblClickNode = function(selectedNode){ -+ if($scope.onDblclick!=null){ -+ $scope.onDblclick({node:selectedNode}); -+ } -+ } -+ -+ $scope.selectedClass = function() { -+ var isThisNodeSelected = isSelectedNode(this.node); -+ var labelSelectionClass = classIfDefined($scope.options.injectClasses.labelSelected, false); -+ var injectSelectionClass = ""; -+ if (labelSelectionClass && isThisNodeSelected) -+ injectSelectionClass = " " + labelSelectionClass; -+ -+ return isThisNodeSelected?"tree-selected" + injectSelectionClass:""; -+ }; -+ -+ //tree template -+ var orderBy = $scope.orderBy ? ' | orderBy:orderBy:reverseOrder' : ''; -+ var template = -+ '<ul '+classIfDefined($scope.options.injectClasses.ul, true)+'>' + -+ '<li ng-repeat="node in node.' + $scope.options.nodeChildren + ' | filter:filterExpression:filterComparator ' + orderBy + '" ng-class="headClass(node)" '+classIfDefined($scope.options.injectClasses.li, true)+'>' + -+ '<i class="tree-branch-head" ng-class="iBranchClass()" ng-click="selectNodeHead(node)"></i>' + -+ '<i class="tree-leaf-head '+classIfDefined($scope.options.injectClasses.iLeaf, false)+'"></i>' + -+ '<div class="tree-label '+classIfDefined($scope.options.injectClasses.label, false)+'" ng-class="selectedClass()" ng-click="selectNodeLabel(node)" ng-dblclick="dblClickNode(node)" tree-transclude></div>' + -+ '<treeitem ng-if="nodeExpanded()"></treeitem>' + -+ '</li>' + -+ '</ul>'; -+ -+ this.template = $compile(template); -+ }], -+ compile: function(element, attrs, childTranscludeFn) { -+ return function ( scope, element, attrs, treemodelCntr ) { -+ -+ scope.$watch("treeModel", function updateNodeOnRootScope(newValue) { -+ if (angular.isArray(newValue)) { -+ if (angular.isDefined(scope.node) && angular.equals(scope.node[scope.options.nodeChildren], newValue)) -+ return; -+ scope.node = {}; -+ scope.synteticRoot = scope.node; -+ scope.node[scope.options.nodeChildren] = newValue; -+ } -+ else { -+ if (angular.equals(scope.node, newValue)) -+ return; -+ scope.node = newValue; -+ } -+ }); -+ -+ scope.$watchCollection('expandedNodes', function(newValue) { -+ var notFoundIds = 0; -+ var newExpandedNodesMap = {}; -+ var $liElements = element.find('li'); -+ var existingScopes = []; -+ // find all nodes visible on the tree and the scope $id of the scopes including them -+ angular.forEach($liElements, function(liElement) { -+ var $liElement = angular.element(liElement); -+ var liScope = $liElement.scope(); -+ existingScopes.push(liScope); -+ }); -+ // iterate over the newValue, the new expanded nodes, and for each find it in the existingNodesAndScopes -+ // if found, add the mapping $id -> node into newExpandedNodesMap -+ // if not found, add the mapping num -> node into newExpandedNodesMap -+ angular.forEach(newValue, function(newExNode) { -+ var found = false; -+ for (var i=0; (i < existingScopes.length) && !found; i++) { -+ var existingScope = existingScopes[i]; -+ if (scope.options.equality(newExNode, existingScope.node)) { -+ newExpandedNodesMap[existingScope.$id] = existingScope.node; -+ found = true; -+ } -+ } -+ if (!found) -+ newExpandedNodesMap[notFoundIds++] = newExNode; -+ }); -+ scope.expandedNodesMap = newExpandedNodesMap; -+ }); -+ -+// scope.$watch('expandedNodesMap', function(newValue) { -+// -+// }); -+ -+ //Rendering template for a root node -+ treemodelCntr.template( scope, function(clone) { -+ element.html('').append( clone ); -+ }); -+ // save the transclude function from compile (which is not bound to a scope as apposed to the one from link) -+ // we can fix this to work with the link transclude function with angular 1.2.6. as for angular 1.2.0 we need -+ // to keep using the compile function -+ scope.$treeTransclude = childTranscludeFn; -+ } -+ } -+ }; -+ }]) -+ .directive("treeitem", function() { -+ return { -+ restrict: 'E', -+ require: "^treecontrol", -+ link: function( scope, element, attrs, treemodelCntr) { -+ // Rendering template for the current node -+ treemodelCntr.template(scope, function(clone) { -+ element.html('').append(clone); -+ }); -+ } -+ } -+ }) -+ .directive("treeTransclude", function() { -+ return { -+ link: function(scope, element, attrs, controller) { -+ if (!scope.options.isLeaf(scope.node)) { -+ angular.forEach(scope.expandedNodesMap, function (node, id) { -+ if (scope.options.equality(node, scope.node)) { -+ scope.expandedNodesMap[scope.$id] = scope.node; -+ scope.expandedNodesMap[id] = undefined; -+ } -+ }); -+ } -+ if (!scope.options.multiSelection && scope.options.equality(scope.node, scope.selectedNode)) { -+ scope.selectedNode = scope.node; -+ } else if (scope.options.multiSelection) { -+ var newSelectedNodes = []; -+ for (var i = 0; (i < scope.selectedNodes.length); i++) { -+ if (scope.options.equality(scope.node, scope.selectedNodes[i])) { -+ newSelectedNodes.push(scope.node); -+ } -+ } -+ scope.selectedNodes = newSelectedNodes; -+ } -+ -+ // create a scope for the transclusion, whos parent is the parent of the tree control -+ scope.transcludeScope = scope.parentScopeOfTree.$new(); -+ scope.transcludeScope.node = scope.node; -+ scope.transcludeScope.$parentNode = (scope.$parent.node === scope.synteticRoot)?null:scope.$parent.node; -+ scope.transcludeScope.$index = scope.$index; -+ scope.transcludeScope.$first = scope.$first; -+ scope.transcludeScope.$middle = scope.$middle; -+ scope.transcludeScope.$last = scope.$last; -+ scope.transcludeScope.$odd = scope.$odd; -+ scope.transcludeScope.$even = scope.$even; -+ scope.$on('$destroy', function() { -+ scope.transcludeScope.$destroy(); -+ }); -+ -+ scope.$treeTransclude(scope.transcludeScope, function(clone) { -+ element.empty(); -+ element.append(clone); -+ }); -+ } -+ } -+ }); -+})( angular ); -diff --git a/webapp/app/js/services/kylinProperties.js b/webapp/app/js/services/kylinProperties.js -index a03403b..b1f04c0 100644 ---- a/webapp/app/js/services/kylinProperties.js -+++ b/webapp/app/js/services/kylinProperties.js -@@ -20,6 +20,7 @@ KylinApp.service('kylinConfig', function (AdminService, $log) { - var _config; - var timezone; - var deployEnv; -+ var hiveLimit; - - - this.init = function () { -@@ -56,12 +57,22 @@ KylinApp.service('kylinConfig', function (AdminService, $log) { - } - - this.getDeployEnv = function () { -+ this.deployEnv = this.getProperty("deploy.env"); - if (!this.deployEnv) { -- this.deployEnv = this.getProperty("deploy.env").trim(); -+ return "DEV"; - } -- return this.deployEnv.toUpperCase(); -+ return this.deployEnv.toUpperCase().trim(); - } - -+ this.getHiveLimit = function () { -+ this.hiveLimit = this.getProperty("kylin.web.hive.limit"); -+ if (!this.hiveLimit) { -+ return 20; -+ } -+ return this.hiveLimit; -+ } -+ -+ - //fill config info for Config from backend - this.initWebConfigInfo = function () { - -diff --git a/webapp/app/js/services/tables.js b/webapp/app/js/services/tables.js -index 3b5e9f4..9b2d376 100755 ---- a/webapp/app/js/services/tables.js -+++ b/webapp/app/js/services/tables.js -@@ -17,13 +17,14 @@ - */ - - KylinApp.factory('TableService', ['$resource', function ($resource, config) { -- return $resource(Config.service.url + 'tables/:tableName/:action', {}, { -+ return $resource(Config.service.url + 'tables/:tableName/:action/:database', {}, { - list: {method: 'GET', params: {}, cache: true, isArray: true}, - get: {method: 'GET', params: {}, isArray: false}, - getExd: {method: 'GET', params: {action: 'exd-map'}, isArray: false}, - reload: {method: 'PUT', params: {action: 'reload'}, isArray: false}, - loadHiveTable: {method: 'POST', params: {}, isArray: false}, - addStreamingSrc: {method: 'POST', params: {action:'addStreamingSrc'}, isArray: false}, -- genCardinality: {method: 'PUT', params: {action: 'cardinality'}, isArray: false} -- }); -+ genCardinality: {method: 'PUT', params: {action: 'cardinality'}, isArray: false}, -+ showHiveDatabases: {method: 'GET', params: {action:'hive'}, cache: true, isArray: true}, -+ showHiveTables: {method: 'GET', params: {action:'hive'}, cache: true, isArray: true} }); - }]); -diff --git a/webapp/app/partials/tables/source_table_tree.html b/webapp/app/partials/tables/source_table_tree.html -index 767eb43..c091dca 100755 ---- a/webapp/app/partials/tables/source_table_tree.html -+++ b/webapp/app/partials/tables/source_table_tree.html -@@ -26,6 +26,7 @@ - <div class="col-xs-5" style="padding-left: 0px;margin-top: 20px;"> - <div class="pull-right"> - <a class="btn btn-xs btn-primary" tooltip="Load Hive Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openModal()"><i class="fa fa-download"></i></a> -+ <a class="btn btn-xs btn-info" tooltip="Load Hive Table From Tree" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openTreeModal()"><i class="fa fa-download"></i></a> - <a class="btn btn-xs btn-primary" tooltip="Add Streaming Table" ng-if="userService.hasRole('ROLE_ADMIN')" ng-click="openStreamingSourceModal()"><i class="fa fa-area-chart"></i></a> - </div> - </div> -@@ -47,3 +48,28 @@ - </div> - - <div ng-include="'partials/tables/table_load.html'"></div> -+ -+<script type="text/ng-template" id="addHiveTableFromTree.html"> -+ <div class="modal-header"><button class="close" type="button" data-dismiss="modal" ng-click="cancel()">Ã</button> -+ <h4>Load Hive Table Metadata From Tree</h4> -+ </div> -+ <div class="modal-body"> -+ <span><strong>Project: </strong>{{ $parent.projectName!=null?$parent.projectName:'NULL'}}</span> -+ <div class="form-group searchBox"> -+ <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="predicate" /> -+ </div> -+ <loading ng-if="!hiveLoaded" text="Loading Databases..."></loading> -+ <treecontrol class="tree-light check" tree-model="treedata" selected-nodes="selectedNodes" filter-expression="predicate" on-selection="showSelected(node)" on-node-toggle="showToggle(node)" options="treeOptions"> -+ <div ng-if="node.label==''&&node.id==0"><img src="image/ajax-loader.gif">Loading Tables...</div> -+ <button class="btn btn-xs btn-primary" ng-if="node.label==''&&node.id==65535" ng-click="showMoreClicked($parentNode)">Show More</button> -+ <button class="btn btn-xs btn-primary" ng-if="node.label==''&&node.id==65535" ng-click="showAllClicked($parentNode)">Show All</button> -+ {{node.label}} -+ </treecontrol> -+ </div> -+ -+ <div class="modal-footer"> -+ <button class="btn btn-primary" ng-click="add()">Sync</button> -+ <button class="btn btn-primary" ng-click="cancel()">Cancel</button> -+ </div> -+ -+</script> -diff --git a/webapp/bower.json b/webapp/bower.json -index 41144f9..bba4a52 100755 ---- a/webapp/bower.json -+++ b/webapp/bower.json -@@ -32,7 +32,8 @@ - "bootstrap-sweetalert": "~0.4.3", - "angular-toggle-switch":"1.3.0", - "angular-ui-select": "0.13.2", -- "angular-sanitize": "1.2.18" -+ "angular-sanitize": "1.2.18", -+ "angular-tree-control": "0.2.8" - }, - "devDependencies": { - "less.js": "~1.4.0", -diff --git a/webapp/grunt.json b/webapp/grunt.json -index 3219b5e..86ad1dc 100755 ---- a/webapp/grunt.json -+++ b/webapp/grunt.json -@@ -19,7 +19,6 @@ - "app/components/angularLocalStorage/src/angularLocalStorage.js", - "app/components/angular-base64/angular-base64.min.js", - "app/components/ng-grid/build/ng-grid.js", -- "app/components/angular-tree-control/angular-tree-control.js", - "app/components/ace-builds/src-min-noconflict/ace.js", - "app/components/ace-builds/src-min-noconflict/ext-language_tools.js", - "app/components/ace-builds/src-min-noconflict/mode-json.js", --- -2.5.4 (Apple Git-61) -