Pārlūkot izejas kodu

[security] Added privileges filter and load more

Enrico Berti 11 gadi atpakaļ
vecāks
revīzija
ba2530d

+ 1 - 0
apps/beeswax/src/beeswax/urls.py

@@ -58,6 +58,7 @@ urlpatterns += patterns(
   'beeswax.api',
 
   url(r'^api/autocomplete/$', 'autocomplete', name='api_autocomplete_databases'),
+  url(r'^api/autocomplete/(?P<database>\w+)$', 'autocomplete', name='api_autocomplete_tables'),
   url(r'^api/autocomplete/(?P<database>\w+)/$', 'autocomplete', name='api_autocomplete_tables'),
   url(r'^api/autocomplete/(?P<database>\w+)/(?P<table>\w+)$', 'autocomplete', name='api_autocomplete_columns'),
   url(r'^api/autocomplete/(?P<database>\w+)/(?P<table>\w+)/$', 'autocomplete', name='api_autocomplete_columns'),

+ 2 - 1
apps/security/src/security/templates/hdfs.mako

@@ -110,7 +110,6 @@ ${ layout.menubar(section='hdfs') }
                     <i class="fa fa-group" title="List of groups in popover for this user?"></i>
                   </div>
                   <div>
-                    <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
                     <a class="pointer" data-bind="click: $root.assist.collapseOthers" rel="tooltip" data-placement="right" title="${_('Close other nodes')}">
                       <i class="fa fa-compress"></i>
                     </a>
@@ -122,6 +121,8 @@ ${ layout.menubar(section='hdfs') }
                     <a class="pointer" data-bind="visible: $root.assist.checkedItems().length > 0, click: function(){ $('#bulkActionsModal').modal('show'); }" rel="tooltip" data-placement="right" title="${ _('Add, replace or remove ACLs for the checked paths') }">
                       <i class="fa fa-copy"></i>
                     </a>
+                    &nbsp;
+                    <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
                   </div>
                 </div>
               </div>

+ 16 - 7
apps/security/src/security/templates/hive.mako

@@ -28,9 +28,12 @@ ${ layout.menubar(section='hive') }
 
 
 <script type="text/html" id="role">
-  <div class="acl-block-title"><i class="fa fa-cube muted"></i> <a class="pointer" data-bind="click: function(){  $root.showRole($data); }"><span data-bind="text: name"></span></a></div>
-  <div data-bind="template: { name: 'privilege', foreach: privileges }"></div>
-  <div class="acl-block acl-actions" data-bind="click: privilegesChanged().length == 0 ? addPrivilege : void(0)">
+  <div class="acl-block-title">
+    <i class="fa fa-cube muted"></i> <a class="pointer" data-bind="click: function(){  $root.showRole($data); }"><span data-bind="text: name"></span></a>
+  </div>
+  <div data-bind="template: { name: 'privilege', foreach: privilegesForView }"></div>
+  <div class="acl-block acl-actions">
+    <span class="pointer" data-bind="visible: privilegesForViewTo() < privileges().length, click: function(){ privilegesForViewTo(privilegesForViewTo() + 50) }" title="${ _('Show 50 more...') }"><i class="fa fa-ellipsis-h"></i></span>
     <span class="pointer" data-bind="click: addPrivilege" title="${ _('Add privilege') }"><i class="fa fa-plus"></i></span>
     <span class="pointer" data-bind="click: $root.list_sentry_privileges_by_authorizable, visible: privilegesChanged().length > 0" title="${ _('Undo') }"> &nbsp; <i class="fa fa-undo"></i></span>
     <span class="pointer" data-bind="click: $root.role.savePrivileges, visible: privilegesChanged().length > 0" title="${ _('Save') }"> &nbsp; <i class="fa fa-save"></i></span>
@@ -150,7 +153,6 @@ ${ layout.menubar(section='hive') }
                     <i class="fa fa-group" title="${ _('List of groups in popover for this user?') }"></i>
                   </div>
                   <div>
-                    <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
                     <a class="pointer" data-bind="click: $root.assist.collapseOthers" rel="tooltip" data-placement="right" title="${_('Close other nodes')}">
                       <i class="fa fa-compress"></i>
                     </a>
@@ -162,6 +164,8 @@ ${ layout.menubar(section='hive') }
                     <a class="pointer" data-bind="visible: $root.assist.checkedItems().length > 0, click: function(){ $('#bulkActionsModal').modal('show'); }" rel="tooltip" data-placement="right" title="${ _('Add, replace or remove ACLs for the checked paths') }">
                       <i class="fa fa-copy"></i>
                     </a>
+                    &nbsp;
+                    <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
                   </div>
 
                 </div>
@@ -172,9 +176,13 @@ ${ layout.menubar(section='hive') }
             </div>
             <div class="span6 acl-panel">
               <div class="acl-panel-content">
-                <a data-bind="visible: $root.assist.privileges().length > 0, click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }" class="btn pointer pull-right"><i class="fa fa-plus-circle"></i> ${ _('Add role') }</a>
-                <h4 style="margin-top: 4px">${ _('Privileges') }</h4>
-                <div data-bind="visible: $root.assist.privileges().length == 0"><em class="muted">${ _('No privileges found for the selected item.')} <a class="pointer" data-bind="click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }">${ _('Click here to add a new role.') }</a> </em></div>
+                <div class="pull-right">
+                  <input class="input-medium no-margin" type="text" placeholder="${ _('Search privileges...') }" data-bind="value: privilegeFilter, valueUpdate: 'afterkeydown', visible: $root.assist.privileges().length > 1"> &nbsp;
+                  <a data-bind="visible: $root.assist.privileges().length > 0, click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }" class="btn pointer"><i class="fa fa-plus-circle"></i> ${ _('Add role') }</a>
+                </div>
+                <h4 style="margin-top: 4px">${ _('Privileges') } &nbsp;<i class="fa fa-spinner fa-spin" data-bind="visible: $root.isLoadingPrivileges()"></i></h4>
+                <div data-bind="visible: $root.assist.privileges().length == 0 && ! $root.isLoadingPrivileges()"><em class="muted">${ _('No privileges found for the selected item.')} <a class="pointer" data-bind="click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }">${ _('Click here to add a new role.') }</a> </em></div>
+                <div data-bind="visible: $root.assist.privileges().length == 0 && $root.isLoadingPrivileges()"><em class="muted">${ _('Loading privileges...')}</em></div>
                 <div data-bind="template: { name: 'role', foreach: $root.assist.roles }"></div>
               </div>
             </div>
@@ -418,6 +426,7 @@ ${ tree.import_templates(itemClick='$root.assist.setPath', iconClick='$root.assi
 
 
   <script type="text/javascript" charset="utf-8">
+
     var viewModel = new HiveViewModel(${ initial | n,unicode });
     ko.applyBindings(viewModel);
 

+ 9 - 1
apps/security/static/js/common.ko.js

@@ -164,4 +164,12 @@ function getFileBrowseButton(inputElement, selectFolder) {
       inputElement.change();
     }
   });
-}
+}
+
+ko.bindingHandlers.tooltip = {
+  update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+    var options = ko.utils.unwrapObservable(valueAccessor());
+    var self = $(element);
+    self.tooltip(options);
+  }
+};

+ 36 - 6
apps/security/static/js/hive.ko.js

@@ -124,6 +124,7 @@ var Role = function (vm, role) {
     self.originalGroups.push(group);
   });
   self.privileges = ko.observableArray(); // Not included in the API
+  self.privilegesForViewTo = ko.observable(49);
   self.originalPrivileges = ko.observableArray();
   self.showPrivileges = ko.observable(false);
   self.showEditGroups = ko.observable(false);
@@ -139,6 +140,19 @@ var Role = function (vm, role) {
     return !($(self.groups()).not(self.originalGroups()).length == 0 && $(self.originalGroups()).not(self.groups()).length == 0);
   });
 
+  self.privilegesForView = ko.computed(function() {
+    var _filter = vm.privilegeFilter().toLowerCase();
+    if (_filter == "") {
+      return self.privileges().slice(0, self.privilegesForViewTo());
+    }
+    else {
+      var _filtered = ko.utils.arrayFilter(self.privileges(), function (priv) {
+        return priv.dbName().toLowerCase().indexOf(_filter) > -1 || priv.tableName().toLowerCase().indexOf(_filter) > -1 || priv.action().toLowerCase().indexOf(_filter) > -1;
+      });
+      return _filtered.slice(0, self.privilegesForViewTo());
+    }
+  });
+
   self.reset = function () {
     self.name('');
     self.groups.removeAll();
@@ -473,7 +487,12 @@ var Assist = function (vm, initial) {
     }
     self.path(obj.path());
     $(document).trigger("changed.path");
-    self.fetchHivePath();
+    if (self.getTreeAdditionalDataForPath(obj.path()).loaded){
+      vm.list_sentry_privileges_by_authorizable();
+    }
+    else {
+      self.fetchHivePath();
+    }
   }
 
   self.togglePath = function (obj) {
@@ -572,6 +591,7 @@ var Assist = function (vm, initial) {
   }
 
   self.fetchHivePath = function (optionalPath, loadCallback) {
+    self.isLoadingTree(true);
     var _originalPath = typeof optionalPath != "undefined" ? optionalPath : self.path();
     if (_originalPath.split(".").length < 3) {
       var _path = _originalPath.replace('.', '/');
@@ -590,9 +610,11 @@ var Assist = function (vm, initial) {
             if (vm.getPathHash() == ""){
               self.setPath(self.treeData().nodes()[0]);
             }
-          } else if (data.tables && data.tables.length > 0) {
+          }
+          else if (data.tables && data.tables.length > 0) {
             self.addTables(_originalPath, data.tables, _hasCallback);
           }
+          self.isLoadingTree(false);
           //else if (data.columns && data.columns.length > 0) {
             //self.addColumns(_originalPath, data.columns, _hasCallback);
           //}
@@ -623,9 +645,13 @@ var Assist = function (vm, initial) {
 var HiveViewModel = function (initial) {
   var self = this;
 
+  self.isLoadingPrivileges = ko.observable(false);
+
   self.availablePrivileges = ko.observableArray(['SERVER', 'DATABASE', 'TABLE']);
   self.availableActions = ko.observableArray(['SELECT', 'INSERT', 'ALL']);
 
+  self.privilegeFilter = ko.observable("");
+
   // Models
   self.roles = ko.observableArray();
   self.roleFilter = ko.observable("");
@@ -726,10 +752,10 @@ var HiveViewModel = function (initial) {
   };
 
   self.init = function (path) {
+    self.assist.isLoadingTree(true);
     self.fetchUsers();
     self.assist.path(path);
     self.list_sentry_roles_by_group();
-
     if (path != "") {
       self.assist.loadParents();
     } else {
@@ -831,7 +857,10 @@ var HiveViewModel = function (initial) {
   }
 
   self.list_sentry_privileges_by_authorizable = function () {
+    self.isLoadingPrivileges(true);
     if (self.assist.path() != "") {
+      self.assist.roles.removeAll();
+      self.assist.privileges.removeAll();
       $.ajax({
         type: "POST",
         url: "/security/api/hive/list_sentry_privileges_by_authorizable",
@@ -841,8 +870,7 @@ var HiveViewModel = function (initial) {
           authorizableHierarchy: ko.mapping.toJSON(_create_authorizable_from_ko())
         },
         success: function (data) {
-          self.assist.roles.removeAll();
-          self.assist.privileges.removeAll();
+          var _privileges = [];
           $.each(data.privileges, function (index, item) {
             var _role = null;
             self.assist.roles().forEach(function (role) {
@@ -855,8 +883,10 @@ var HiveViewModel = function (initial) {
               _role = self.assist.roles()[_idx - 1];
             }
             _role.privileges.push(_create_ko_privilege(item));
-            self.assist.privileges.push(_create_ko_privilege(item));
+            _privileges.push(_create_ko_privilege(item));
           });
+          self.assist.privileges(_privileges);
+          self.isLoadingPrivileges(false);
         }
       }).fail(function (xhr, textStatus, errorThrown) {
         $(document).trigger("error", xhr.responseText);

+ 4 - 0
desktop/core/static/css/hue3.css

@@ -1741,3 +1741,7 @@ border-bottom-left-radius: 0px;
 .fa-1halfx {
   font-size: 1.5em;
 }
+
+input.no-margin {
+  margin-bottom: 0;
+}