Explorar o código

[security] Added collapse, expand and refresh tree

Enrico Berti %!s(int64=11) %!d(string=hai) anos
pai
achega
ef5c7a1

+ 44 - 18
apps/security/src/security/templates/hdfs.mako

@@ -71,10 +71,41 @@ ${ layout.menubar(section='hdfs') }
   }
 
   .acl-panel {
-    border-left: 1px solid #CCC;
+    border-left: 1px solid #e5e5e5;
     padding-top: 6px;
-    padding-left: 6px;
+    padding-left: 12px;
     min-height: 300px;
+    margin-left: 12px;
+  }
+
+  #path {
+    width: 96%;
+    height: 40px;
+    font-size: 14pt;
+  }
+
+  .path-container .btn-inverse {
+    height: 40px;
+    width: 40px;
+    font-size: 14pt;
+    line-height: 40px;
+  }
+
+  .fake-pre {
+    display: block;
+    padding: 9.5px;
+    margin: 0 0 10px;
+    font-size: 12px;
+    line-height: 20px;
+    word-break: break-all;
+    word-wrap: break-word;
+    font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
+    background-color: #f5f5f5;
+    border: 1px solid #ccc;
+    border: 1px solid rgba(0, 0, 0, 0.15);
+    -webkit-border-radius: 2px;
+    -moz-border-radius: 2px;
+    border-radius: 2px;
   }
 
 </style>
@@ -127,34 +158,29 @@ ${ layout.menubar(section='hdfs') }
             <div class="span8">
               <div class="path-container">
                 <div class="input-append span12">
-                  <input id="path" type="text" style="width: 96%; height: 40px; font-size: 14pt" data-bind="value: $root.assist.path, valueUpdate: 'afterkeydown'" autocomplete="off"/>
+                  <input id="path" type="text" data-bind="value: $root.assist.path, valueUpdate: 'afterkeydown'" autocomplete="off"/>
                   <a data-bind="attr: { href: '/filebrowser/view' + $root.assist.path() }" target="_blank" title="${ _('Open in File Browser') }" class="btn btn-inverse">
                     <i class="fa fa-external-link"></i>
                   </a>
                 </div>
+                <div class="clearfix"></div>
               </div>
               <div class="path-container-ghost hide"></div>
               ${ tree.render(id='hdfsTree', data='$root.assist.treeData', afterRender='$root.assist.afterRender') }
             </div>
             <div class="span4">
               <div class="acl-panel" data-bind="visible: ! $root.assist.isLoadingAcls()">
-                  <a href="javascript: void(0)" data-bind="click: function() { $root.assist.showAclsAsText(! $root.assist.showAclsAsText()); }">
-                    <i class="fa fa-2x" data-bind="css: { 'fa-header': $root.assist.showAclsAsText(), 'fa-pencil': ! $root.assist.showAclsAsText() }"></i>
-                    <span data-bind="visible: $root.assist.showAclsAsText()">${ _('Text view') }</span>
-                    <span data-bind="visible: ! $root.assist.showAclsAsText()">${ _('Edit') }</span>
-                  </a>
 
-                  <br/>
+                  <ul class="nav nav-tabs">
+                    <li data-bind="css: {'active': ! $root.assist.showAclsAsText()}"><a href="javascript: void(0)" data-bind="click: function() { $root.assist.showAclsAsText(false); }"><i class="fa fa-pencil"></i> ${ _('Edit') }</a></li>
+                    <li data-bind="css: {'active': $root.assist.showAclsAsText()}"><a href="javascript: void(0)" data-bind="click: function() { $root.assist.showAclsAsText(true); }"><i class="fa fa-header"></i> ${ _('View as text') }</a></li>
+                  </ul>
 
-                  <span data-bind="visible: $root.assist.showAclsAsText">
-                    <br/>
-                    # file: <span data-bind="text: $root.assist.path"></span>
-                    <br/>
-                    # owner: <span data-bind="text: $root.assist.owner"></span>
-                    <br/>
-                    # group: <span data-bind="text: $root.assist.group"></span>
-                    <br/>                  
-                    <div data-bind="foreach: $root.assist.regularAcls">                    
+                  <span class="fake-pre" data-bind="visible: $root.assist.showAclsAsText">
+                    # file: <span data-bind="text: $root.assist.path"></span><br/>
+                    # owner: <span data-bind="text: $root.assist.owner"></span><br/>
+                    # group: <span data-bind="text: $root.assist.group"></span><br/>
+                    <div data-bind="foreach: $root.assist.regularAcls">
                       <div data-bind="template: {name: 'acl-display'}"></div>
                     </div>
                     <div data-bind="foreach: $root.assist.defaultAcls">

+ 83 - 45
apps/security/static/js/hdfs.ko.js

@@ -65,19 +65,21 @@ var Assist = function (vm, assist) {
   self.isDiffMode = ko.observable(false);
 
   self.treeAdditionalData = {};
-  self.treeAdditionalDataObservable = ko.observable({});
   self.treeData = ko.observable({nodes: []});
   self.loadData = function (data) {
     self.treeData(new TreeNodeModel(data));
   };
 
-  self.growingTree = ko.observable({
+  self.initialGrowingTree = {
     name: "__HUEROOT__",
     path: "__HUEROOT__",
     aclBit: false,
     striked: false,
     selected: false,
-    page: {},
+    page: {
+      number: -1,
+      num_pages: -1
+    },
     nodes: [
       {
         name: "/",
@@ -87,11 +89,16 @@ var Assist = function (vm, assist) {
         aclBit: false,
         striked: false,
         selected: false,
-        page: {},
+        page: {
+          number: -1,
+          num_pages: -1
+        },
         nodes: []
       }
     ]
-  });
+  };
+
+  self.growingTree = ko.observable(jQuery.extend(true, {}, self.initialGrowingTree));
 
   self.path = ko.observable('');
   self.path.subscribe(function (path) {
@@ -182,7 +189,10 @@ var Assist = function (vm, assist) {
         striked: item.striked != null,
         isExpanded: true,
         isDir: item.type == "dir",
-        page: {},
+        page: {
+          number: -1,
+          num_pages: -1
+        },
         nodes: []
       });
     }
@@ -192,11 +202,9 @@ var Assist = function (vm, assist) {
   self.getTreeAdditionalDataForPath = function (path) {
     if (typeof self.treeAdditionalData[path] == "undefined"){
       var _add = {
-        loaded: false,
-        page: {}
+        loaded: false
       }
       self.treeAdditionalData[path] = _add;
-      self.treeAdditionalDataObservable(self.treeAdditionalData);
     }
     return self.treeAdditionalData[path];
   }
@@ -213,8 +221,39 @@ var Assist = function (vm, assist) {
     return leaf;
   }
 
+  self.updateTreeProperty = function (leaf, property, value) {
+    leaf[property] = value;
+    if (leaf.nodes.length > 0) {
+      leaf.nodes.forEach(function (node) {
+        self.updateTreeProperty(node, property, value);
+      });
+    }
+    return leaf;
+  }
+
+  self.collapseTree = function () {
+    self.updateTreeProperty(self.growingTree(), "isExpanded", false);
+    self.updatePathProperty(self.growingTree(), "/", "isExpanded", true);
+    self.loadData(self.growingTree());
+  }
+
+  self.expandTree = function () {
+    self.updateTreeProperty(self.growingTree(), "isExpanded", true);
+    self.loadData(self.growingTree());
+  }
+
+  self.refreshTree = function () {
+    self.growingTree(jQuery.extend(true, {}, self.initialGrowingTree));
+    Object.keys(self.treeAdditionalData).forEach(function (path) {
+      if (self.treeAdditionalData[path].loaded) {
+        console.log("Fetching", path);
+        self.fetchPath(path);
+      }
+    });
+  }
+
   self.setPath = function (obj) {
-    if (self.getTreeAdditionalDataForPath(obj.path()).loaded == true) {
+    if (self.getTreeAdditionalDataForPath(obj.path()).loaded || (! obj.isExpanded() && ! self.getTreeAdditionalDataForPath(obj.path()).loaded)) {
       obj.isExpanded(!obj.isExpanded());
       self.updatePathProperty(self.growingTree(), obj.path(), "isExpanded", obj.isExpanded());
     }
@@ -241,45 +280,44 @@ var Assist = function (vm, assist) {
     }
   }
 
-  self.fetchPath = function () {
-	$.getJSON('/security/api/hdfs/list' + self.path(), {
-      'pagesize': 15,
-      'pagenum': self.pagenum(),
-      'format': 'json',
-      'doas': vm.doAs(),
-      'isDiffMode': self.isDiffMode()
-    },
-    function (data) {
-      self.getTreeAdditionalDataForPath(self.path()).loaded = true;
-      self.getTreeAdditionalDataForPath(self.path()).page = data.page;
-      self.treeAdditionalDataObservable(self.treeAdditionalData);
-      self.updatePathProperty(self.growingTree(), self.path(), "page", data.page);
-      self.loadParents(data.breadcrumbs);
-      if (data['files'] && data['files'][0] && data['files'][0]['type'] == 'dir') { // Hack for now
-        self.files.removeAll();
-        $.each(data.files, function (index, item) {
-          self.convertItemToObject(item);
-          self.files.push(ko.mapping.fromJS({
-              'path': item.path,
-              'aclBit': item.rwx.indexOf('+') != -1,
-              'striked': item.striked != null
-            })
-          );
-        });
-      }
-      else {
-        self.convertItemToObject(data);
-      }
-      self.loadData(self.growingTree());
-      self.getAcls();
-    }).fail(function (xhr, textStatus, errorThrown) {
-      $(document).trigger("error", xhr.responseText);
-    });
+  self.fetchPath = function (optionalPath) {
+    var _path = typeof optionalPath != "undefined" ? optionalPath : self.path();
+    $.getJSON('/security/api/hdfs/list' + _path, {
+        'pagesize': 15,
+        'pagenum': self.pagenum(),
+        'format': 'json',
+        'doas': vm.doAs(),
+        'isDiffMode': self.isDiffMode()
+      },
+      function (data) {
+        self.loadParents(data.breadcrumbs);
+        if (data['files'] && data['files'][0] && data['files'][0]['type'] == 'dir') { // Hack for now
+          self.files.removeAll();
+          $.each(data.files, function (index, item) {
+            self.convertItemToObject(item);
+            self.files.push(ko.mapping.fromJS({
+                'path': item.path,
+                'aclBit': item.rwx.indexOf('+') != -1,
+                'striked': item.striked != null
+              })
+            );
+          });
+        }
+        else {
+          self.convertItemToObject(data);
+        }
+        self.getTreeAdditionalDataForPath(_path).loaded = true;
+        self.updatePathProperty(self.growingTree(), _path, "page", data.page);
+        self.loadData(self.growingTree());
+        self.getAcls();
+      }).fail(function (xhr, textStatus, errorThrown) {
+        $(document).trigger("error", xhr.responseText);
+      });
   };
 
   self.loadMore = function (what) {
     self.pagenum(what.page().next_page_number());
-    self.fetchPath();
+    self.fetchPath(what.path());
   }
 
   self.getAcls = function () {

+ 43 - 1
desktop/core/static/js/hue.utils.js

@@ -98,4 +98,46 @@ if (!('filter' in Array.prototype)) {
     }
     return this;
   };
-}(hue = window.hue || {}));
+}(hue = window.hue || {}));
+
+
+if (!Object.keys) {
+  Object.keys = (function () {
+    'use strict';
+    var hasOwnProperty = Object.prototype.hasOwnProperty,
+        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
+        dontEnums = [
+          'toString',
+          'toLocaleString',
+          'valueOf',
+          'hasOwnProperty',
+          'isPrototypeOf',
+          'propertyIsEnumerable',
+          'constructor'
+        ],
+        dontEnumsLength = dontEnums.length;
+
+    return function (obj) {
+      if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
+        throw new TypeError('Object.keys called on non-object');
+      }
+
+      var result = [], prop, i;
+
+      for (prop in obj) {
+        if (hasOwnProperty.call(obj, prop)) {
+          result.push(prop);
+        }
+      }
+
+      if (hasDontEnumBug) {
+        for (i = 0; i < dontEnumsLength; i++) {
+          if (hasOwnProperty.call(obj, dontEnums[i])) {
+            result.push(dontEnums[i]);
+          }
+        }
+      }
+      return result;
+    };
+  }());
+}