Browse Source

[security] Tree enhancements

Extracted tree to a customizable library
aclBit files have a more visible blue background
Path is in window.hash and the page can be refreshed
Enrico Berti 11 years ago
parent
commit
0718683227

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

@@ -21,6 +21,7 @@ from django.utils.translation import ugettext as _
 
 
 
 
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
+<%namespace name="tree" file="common_tree.mako" />
 
 
 ${ commonheader(_('Hadoop Security'), "security", user) | n,unicode }
 ${ commonheader(_('Hadoop Security'), "security", user) | n,unicode }
 ${ layout.menubar(section='hdfs') }
 ${ layout.menubar(section='hdfs') }
@@ -151,7 +152,7 @@ ${ layout.menubar(section='hdfs') }
                 </div>
                 </div>
               </div>
               </div>
               <div class="path-container-ghost hide"></div>
               <div class="path-container-ghost hide"></div>
-              <div id="hdfsTree" data-bind="template: { name: 'tree-template', data: $root.assist.treeData }"></div>
+              ${ tree.render(id='hdfsTree', data='$root.assist.treeData') }
             </div>
             </div>
             <div class="span4">
             <div class="span4">
               <div class="acl-panel" data-bind="visible: !$root.assist.isLoadingAcls()">
               <div class="acl-panel" data-bind="visible: !$root.assist.isLoadingAcls()">
@@ -219,66 +220,20 @@ ${ layout.menubar(section='hdfs') }
   </div>
   </div>
 </div>
 </div>
 
 
+<%def name="treeIcons()">
+  'fa-folder-open-o': isDir() && nodes().length > 0,
+  'fa-folder-o': isDir() && nodes().length == 0,
+  'fa-file-o': !isDir()
+</%def>
 
 
+<%def name="aclBitPullRight()">
+  <div class="pull-right" style="margin-right: 20px" data-bind="visible: aclBit()">
+    <i class="fa fa-lock"></i>
+  </div>
+</%def>
 
 
-<script type="text/html" id="tree-template">
-<!-- ko if: nodes != null -->
-<ul class="tree" data-bind="foreach: nodes">
-    <li>
-        <span data-bind="
-            template: { name: 'node-name-template', data: $data }"></span>
-        <div data-bind="template: { name: 'folder-template', data: $data }, visible: isExpanded"></div>
-    </li>    
-</ul>
-<!-- /ko -->
-</script>
-
-<script type="text/html" id="folder-template">
-<!-- ko if: nodes != null -->
-    <ul data-bind="foreach: nodes">
-        <li>
-            <div data-bind="template: { name: 'node-template', data: $data }"></div>
-        </li>
-    ## Should fetch more files here if needed
-    <!-- ko if: $index() == 14 -->
-      <li>
-        <a href="javascript: void(0)">         
-          <i class="fa fa-plus"></i> 
-        </a>
-      </li>
-    <!-- /ko -->        
-    </ul>
-<!-- /ko -->
-</script>
 
 
-<script type="text/html" id="node-template">
-    <!-- ko if: nodes != null -->
-    <span data-bind="
-        template: { name: 'node-name-template', data: $data },
-        css: { 'pointer-icon': nodes().length > 0 }"></span>
-    <!-- /ko -->
-
-    <!-- ko if: nodes().length !== 0 -->
-        <div data-bind="template: { name: 'folder-template', data: $data }, visible: isExpanded"></div>
-    <!-- /ko -->
-</script>
-
-<script type="text/html" id="node-name-template">
-    <div class="node-row" data-bind="click: $root.assist.setPath, event : { dblclick: $root.assist.openPath },  style: { border: aclBit() ? '1px dashed #CCCCCC': '' }, css:{selected: $root.assist.path() == path()}">
-      <i data-bind="
-      css: {
-          'fa': true,
-          'fa-folder-open-o': isDir() && nodes().length > 0,
-          'fa-folder-o': isDir() && nodes().length == 0,
-          'fa-file-o': !isDir()
-      }
-      " style="color: #999"></i>
-      <strong><a style="display: inline-block" data-bind="text:name"></a></strong>
-      <div class="pull-right" style="margin-right: 20px" data-bind="visible: aclBit()">
-        <i class="fa fa-lock"></i>
-      </div>
-    </div>
-</script>
+${ tree.import_templates(itemClick='$root.assist.setPath', itemDblClick='$root.assist.openPath', itemSelected='$root.assist.path() == path()', iconModifier=treeIcons, styleModifier='aclBit', styleModifierPullRight=aclBitPullRight) }
 
 
 
 
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
@@ -310,7 +265,11 @@ ${ layout.menubar(section='hdfs') }
     viewModel = new HdfsViewModel(${ initial | n,unicode });
     viewModel = new HdfsViewModel(${ initial | n,unicode });
     ko.applyBindings(viewModel);
     ko.applyBindings(viewModel);
 
 
-    viewModel.init();
+    var _initialPath = "/";
+    if (window.location.hash != ""){
+      _initialPath = window.location.hash.substr(1);
+    }
+    viewModel.init(_initialPath);
 
 
     //$(document).on("loaded.acls", movePopover);
     //$(document).on("loaded.acls", movePopover);
 
 

+ 20 - 33
apps/security/static/js/hdfs.ko.js

@@ -59,20 +59,28 @@ var Assist = function (vm, assist) {
 
 
   self.treeData = ko.observable({nodes:[]});
   self.treeData = ko.observable({nodes:[]});
   self.loadData = function(data) {
   self.loadData = function(data) {
-    self.treeData(new NodeModel(data));
+    self.treeData(new TreeNodeModel(data));
   };
   };
 
 
   self.growingTree = ko.observable({
   self.growingTree = ko.observable({
-    name: "/",
-    path: "/",
+    name: "__HUEROOT__",
+    path: "__HUEROOT__",
     aclBit: false,
     aclBit: false,
     selected: false,
     selected: false,
-    nodes: []
+    nodes: [{
+      name: "/",
+      path: "/",
+      isDir: true,
+      aclBit: false,
+      selected: false,
+      nodes: []
+    }]
   });
   });
 
 
   self.path = ko.observable('');
   self.path = ko.observable('');
-  self.path.subscribe(function () {
+  self.path.subscribe(function (path) {
     self.fetchPath();
     self.fetchPath();
+    window.location.hash = path;
   });
   });
   self.files = ko.observableArray();
   self.files = ko.observableArray();
 
 
@@ -180,7 +188,7 @@ var Assist = function (vm, assist) {
     $.getJSON('/filebrowser/view' + self.path(), {
     $.getJSON('/filebrowser/view' + self.path(), {
       'pagesize': 15,
       'pagesize': 15,
       'format': 'json',
       'format': 'json',
-      'doas': vm.doAs(),
+      'doas': vm.doAs()
     }, function (data) {
     }, function (data) {
       self.loadParents(data.breadcrumbs);
       self.loadParents(data.breadcrumbs);
       if (data['files'] && data['files'][0]['type'] == 'dir') { // Hack for now
       if (data['files'] && data['files'][0]['type'] == 'dir') { // Hack for now
@@ -193,8 +201,11 @@ var Assist = function (vm, assist) {
             })
             })
           );
           );
         });
         });
-        self.loadData(self.growingTree());
       }
       }
+      else {
+        self.convertItemToObject(data);
+      }
+      self.loadData(self.growingTree());
       self.getAcls();
       self.getAcls();
     }).fail(function (xhr, textStatus, errorThrown) {
     }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
       $(document).trigger("error", xhr.responseText);
@@ -261,30 +272,6 @@ var Assist = function (vm, assist) {
 }
 }
 
 
 
 
-var NodeModel = function(data) {
-  var self = this;
-
-  self.isExpanded = ko.observable(true);
-  self.description = ko.observable();
-  self.name = ko.observable();
-  self.nodes = ko.observableArray([]);
-
-  self.toggleVisibility = function() {
-    self.isExpanded(! self.isExpanded());
-  };
-
-  ko.mapping.fromJS(data, self.mapOptions, self);
-};
-
-NodeModel.prototype.mapOptions = {
-  nodes: {
-    create: function(args) {
-      return new NodeModel(args.data);
-    }
-  }
-};
-
-
 var HdfsViewModel = function (initial) {
 var HdfsViewModel = function (initial) {
   var self = this;
   var self = this;
 
 
@@ -297,9 +284,9 @@ var HdfsViewModel = function (initial) {
   self.availableHadoopUsers = ko.observableArray();
   self.availableHadoopUsers = ko.observableArray();
   self.availableHadoopGroups = ko.observableArray();
   self.availableHadoopGroups = ko.observableArray();
 
 
-  self.init = function () {  
+  self.init = function (path) {
     self.fetchUsers();
     self.fetchUsers();
-    self.assist.path('/');
+    self.assist.path(path);
   }
   }
 
 
 
 

+ 116 - 0
desktop/core/src/desktop/templates/common_tree.mako

@@ -0,0 +1,116 @@
+## -*- coding: utf-8 -*-
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+
+
+#
+# Include this in order to use the functions:
+# <%namespace name="tree" file="common_tree.mako" />
+#
+
+<%!
+  from django.utils.translation import ugettext as _
+%>
+
+<%def name="import_templates(itemClick=None, itemDblClick=None, itemSelected=None, iconModifier=None, styleModifier=None, styleModifierPullRight=None, limitCount=None, limitFunction=None)">
+
+  <script src="/static/js/ko.tree.js" type="text/javascript" charset="utf-8"></script>
+
+  <script type="text/html" id="tree-template">
+    <!-- ko if: nodes != null -->
+    <ul class="tree" data-bind="foreach: nodes">
+      <li>
+        <span data-bind="template: { name: 'node-name-template', data: $data }"></span>
+        <div data-bind="template: { name: 'folder-template', data: $data }, visible: isExpanded"></div>
+      </li>
+    </ul>
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="folder-template">
+    <!-- ko if: nodes != null -->
+    <ul data-bind="foreach: nodes">
+      <li>
+        <div data-bind="template: { name: 'node-template', data: $data }"></div>
+      </li>
+      <!-- ko if: $index() == 14 -->
+      <li>
+        <a href="javascript: void(0)">
+          <i class="fa fa-plus"></i>
+        </a>
+      </li>
+      <!-- /ko -->
+    </ul>
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="node-template">
+    <!-- ko if: nodes != null -->
+    <span data-bind="
+          template: { name: 'node-name-template', data: $data },
+          css: { 'pointer-icon': nodes().length > 0 }"></span>
+    <!-- /ko -->
+
+    <!-- ko if: nodes().length !== 0 -->
+    <div data-bind="template: { name: 'folder-template', data: $data }, visible: isExpanded"></div>
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="node-name-template">
+    <div class="node-row" data-bind="
+    %if itemClick:
+      click: ${itemClick},
+    %endif
+    %if itemDblClick:
+      event : { dblclick: ${itemDblClick} },
+    %endif
+    %if styleModifier:
+      style: { border: ${styleModifier}() ? '1px dashed #bce8f1': '',  background: ${styleModifier}() ? '#d9edf7': ''},
+    %endif
+    %if itemSelected:
+     css:{selected: ${itemSelected}}">
+    %else:
+     css:{unselected: true">
+    %endif
+      <i data-bind="
+        css: {
+            'fa': true,
+            %if iconModifier:
+            ${iconModifier()}
+            %else:
+            'fa-file-o': true
+            %endif
+        },
+        %if styleModifier:
+          style: { color: ${styleModifier}() ? '#338bb8': '#999999'}
+        %else:
+          style: { color: '#999999'}
+        %endif
+        "></i>
+      <strong><a style="display: inline-block" data-bind="text:name"></a></strong>
+
+      %if styleModifierPullRight:
+      ${styleModifierPullRight()}
+      %endif
+    </div>
+  </script>
+
+</%def>
+
+<%def name="render(id=None, data=None)">
+  <div id="${id}" data-bind="template: { name: 'tree-template', data: ${data} }"></div>
+</%def>
+

+ 38 - 0
desktop/core/static/js/ko.tree.js

@@ -0,0 +1,38 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. 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.
+
+var TreeNodeModel = function(data) {
+  var self = this;
+
+  self.isExpanded = ko.observable(true);
+  self.description = ko.observable();
+  self.name = ko.observable();
+  self.nodes = ko.observableArray([]);
+
+  self.toggleVisibility = function() {
+    self.isExpanded(! self.isExpanded());
+  };
+
+  ko.mapping.fromJS(data, self.mapOptions, self);
+};
+
+TreeNodeModel.prototype.mapOptions = {
+  nodes: {
+    create: function(args) {
+      return new TreeNodeModel(args.data);
+    }
+  }
+};