浏览代码

HUE-950 [core] Initial restyle of the page

Enrico Berti 12 年之前
父节点
当前提交
11edd32f80

二进制
apps/oozie/static/art/icon_oozie_24_bundle.png


二进制
apps/oozie/static/art/icon_oozie_24_coordinator.png


二进制
apps/oozie/static/art/icon_oozie_24_workflow.png


+ 246 - 57
desktop/core/src/desktop/templates/home.mako

@@ -20,79 +20,105 @@
 
 
 ${ commonheader(_('Welcome Home'), "home", user) | n,unicode }
 ${ commonheader(_('Welcome Home'), "home", user) | n,unicode }
 
 
-  <div class="navbar navbar-inverse navbar-fixed-top nokids">
-      <div class="navbar-inner">
-        <div class="container-fluid">
-          <div class="nav-collapse">
-            <ul class="nav">
-              <li class="currentApp">
-                <a href="/home">
-                  <img src="/static/art/home.png" />
-                  ${ _('Home') }
-                </a>
-               </li>
-            </ul>
-          </div>
-        </div>
-      </div>
-  </div>
+<style type="text/css">
+  .sidebar-nav img {
+    margin-right: 6px;
+  }
 
 
-<div style="position: absolute;top:80px;right:30px"><img src="/static/art/hue-logo-subtle.png"/></div>
+  .sidebar-nav .dropdown-menu a {
+    padding-left: 6px;
+  }
 
 
-<div class="container-fluid">
-  <div class="row-fluid">
-    <div class="span12">
-      <h1>${_('Welcome Home.')}</h1>
+  .tag {
+    float: left;
+    margin-right: 6px;
+    margin-bottom: 4px;
+  }
+
+  #trashCounter {
+    margin-top: 3px;
+  }
+
+  .hueCheckbox {
+    margin-right: 6px !important;
+    line-height: 15px !important;
+  }
+
+  .toggleTag {
+    cursor: pointer;
+  }
+</style>
+
+<div class="navbar navbar-inverse navbar-fixed-top nokids">
+  <div class="navbar-inner">
+    <div class="container-fluid">
+      <div class="nav-collapse">
+        <ul class="nav">
+          <li class="currentApp">
+            <a href="/home">
+              <img src="/static/art/home.png" />
+              ${ _('Home') }
+            </a>
+           </li>
+        </ul>
+      </div>
     </div>
     </div>
   </div>
   </div>
-  <div class="row-fluid" style="margin-top: 30px">
+</div>
 
 
+<div class="container-fluid">
+  <div class="row-fluid">
     <div class="span2">
     <div class="span2">
-      <div class="card card-home card-listcontent">
-        <h2 class="card-heading simple">${_('New')}</h2>
-      </div>
-
-      <div class="card card-home card-listcontent">
-        <h2 class="card-heading simple">${_('Tags')}</h2>
+      <div class="sidebar-nav">
+         <ul class="nav nav-list">
+          <li class="nav-header">${_('Actions')}</li>
+           <li class="dropdown">
+              <a href="#" data-toggle="dropdown"><i class="icon-plus-sign"></i> ${_('New document')}</a>
+              <ul class="dropdown-menu" role="menu">
+                <li><a href="#"><img src="/beeswax/static/art/icon_beeswax_24.png"/> ${_('Hive Query')}</a></li>
+                <li><a href="#"><img src="/impala/static/art/icon_impala_24.png"/> ${_('Impala Query')}</a></li>
+                <li><a href="#"><img src="/pig/static/art/icon_pig_24.png"/> ${_('Pig Script')}</a></li>
+                <li class="dropdown-submenu">
+                  <a href="#"><img src="/oozie/static/art/icon_oozie_24.png"/> ${_('Oozie')}</a>
+                  <ul class="dropdown-menu">
+                    <li><a href="#"><img src="/oozie/static/art/icon_oozie_24_workflow.png"/> ${_('Workflow')}</a></li>
+                    <li><a href="#"><img src="/oozie/static/art/icon_oozie_24_coordinator.png"/> ${_('Coordinator')}</a></li>
+                    <li><a href="#"><img src="/oozie/static/art/icon_oozie_24_bundle.png"/> ${_('Bundle')}</a></li>
+                  </ul>
+                </li>
+              </ul>
+           </li>
+           <li class="viewTrash"><a href="javascript:void(0)"><i class="icon-trash"></i> ${_('View Trash')} <span id="trashCounter" class="badge pull-right">0</span></a></li>
+          <li class="nav-header">${_('Tags')}</li>
+          % for tag in tags:
+            %if tag.tag != "trash":
+            <li class="toggleTag white" data-tag="${ tag.tag }"><div class="hueCheckbox pull-left"></div>${ tag.tag }</li>
+            %endif
+          % endfor
 
 
-        <div class="card-body">
-          <p>
-          <ul>
-            % for tag in tags:            
-            <li>
-              <span class="label label-info">${ tag.tag }</span>
-              % if loop.first: 
-                (selected)
-              % endif
-            </li>
-            % endfor
-          </ul>
-          </p>
-        </div>
+        </ul>
       </div>
       </div>
+
     </div>
     </div>
 
 
     <div class="span10">
     <div class="span10">
-      <div class="card card-home card-listcontent">
-        <h2 class="card-heading simple">${_('Documents')}</h2>
+      <div class="card card-home" style="margin-top: 0">
+        <input type="text" placeholder="Search for name, description, etc..." class="input-xlarge search-query pull-right" style="margin-right: 10px;margin-top: 3px" id="filterInput">
+        <h2 class="card-heading simple">${_('My Documents')}</h2>
 
 
         <div class="card-body">
         <div class="card-body">
           <p>
           <p>
-          <table>
-            % for doc in documents:
+          <table class="table table-striped table-condensed datatables" data-tablescroller-disable="true">
+            <thead>
               <tr>
               <tr>
-                <td>${ doc.content_type }</td>
-                <td><a href="${ doc.content_object.get_absolute_url() }">${ doc.name }</a></td>
-                <td>${ doc.description }</td>
-                <td class="span1">
-                  % for tag in doc.tags.all():
-                    <span class="label label-info">${ tag.tag }</span>
-                  % endfor
-                </td>
-                <td class="span1">${ doc.owner }</td>
-                <td class="span1">${ doc.last_modified }</td>
+                <th>&nbsp;</th>
+                <th>${_('Name')}</th>
+                <th>${_('Description')}</th>
+                <th>${_('Tags')}</th>
+                <th>${_('Owner')}</th>
+                <th>${_('Last Modified')}</th>
               </tr>
               </tr>
-            % endfor
+            </thead>
           </table>
           </table>
           </p>
           </p>
         </div>
         </div>
@@ -102,4 +128,167 @@ ${ commonheader(_('Welcome Home'), "home", user) | n,unicode }
   </div>
   </div>
 </div>
 </div>
 
 
+<script src="/static/ext/js/datatables-paging-0.1.js" type="text/javascript" charset="utf-8"></script>
+<script type="text/javascript" charset="utf-8">
+
+  var JSON_DOCS = ${json_documents|n};
+  var documentsTable;
+
+  $(document).ready(function () {
+    documentsTable = $(".datatables").dataTable({
+      "sPaginationType": "bootstrap",
+      "iDisplayLength": 50,
+      "bLengthChange": false,
+      "sDom": "<'row'r>t<'row-fluid'<'dt-pages'p><'dt-records'i>>",
+      "aoColumns": [
+        { "bSortable": false, "sWidth": "26px" },
+        null,
+        null,
+        null,
+        null,
+        { "sSortDataType": "dom-sort-value", "sType": "numeric", "sWidth": "100px" }
+      ],
+      "aaSorting": [
+        [ 1, "desc" ]
+      ],
+      "oLanguage": {
+        "sEmptyTable": "${_('No data available')}",
+        "sInfo": "${_('Showing _START_ to _END_ of _TOTAL_ entries')}",
+        "sInfoEmpty": "${_('Showing 0 to 0 of 0 entries')}",
+        "sInfoFiltered": "${_('(filtered from _MAX_ total entries)')}",
+        "sZeroRecords": "${_('No matching records')}",
+        "oPaginate": {
+          "sFirst": "${_('First')}",
+          "sLast": "${_('Last')}",
+          "sNext": "${_('Next')}",
+          "sPrevious": "${_('Previous')}"
+        }
+      },
+      "fnDrawCallback": function (oSettings) {
+        $("a[data-row-selector='true']").jHueRowSelector();
+      }
+    });
+
+    $("#filterInput").keydown(function (e) {
+      if (e.which == 13) {
+        e.preventDefault();
+        return false;
+      }
+    });
+
+    $("#filterInput").keyup(function () {
+      documentsTable.fnFilter($(this).val());
+      documentsTable.fnDraw();
+    });
+
+    populateTable();
+
+    $(".viewTrash").on("click", function () {
+      $(".hueCheckbox").removeClass("icon-ok");
+      var _this = $(this);
+      if (_this.hasClass("active")) {
+        populateTable();
+        _this.removeClass("active");
+      }
+      else {
+        populateTable("trash");
+        _this.addClass("active");
+      }
+    });
+
+    $(".toggleTag").on("click", function (e) {
+      $(".viewTrash").removeClass("active");
+      var _this = $(this);
+      _this.blur();
+      if (_this.find(".hueCheckbox").hasClass("icon-ok")) {
+        _this.find(".hueCheckbox").removeClass("icon-ok");
+      }
+      else {
+        _this.find(".hueCheckbox").addClass("icon-ok");
+      }
+      var _tags = [];
+      $(".hueCheckbox.icon-ok").each(function () {
+        _tags.push($(this).parent().data("tag"));
+      });
+      populateTable(_tags.join(","));
+    });
+
+    var _trashCounter = 0;
+    $(JSON_DOCS).each(function (cnt, doc) {
+      if (doc.tags.indexOf("trash") > -1) {
+        _trashCounter++;
+      }
+    });
+    $("#trashCounter").text(_trashCounter);
+  });
+
+  function populateTable(tags) {
+    documentsTable.fnClearTable();
+    documentsTable.fnDraw();
+    if (tags == null || tags == "") {
+      $(JSON_DOCS).each(function (cnt, doc) {
+        if (doc.tags.indexOf("trash") == -1) {
+          addRow(doc);
+        }
+      });
+    }
+    else {
+      var _tags = tags.split(",");
+      $(JSON_DOCS).each(function (cnt, doc) {
+        var _add = false;
+        $(_tags).each(function (cnt, tag) {
+          console.log(tag);
+          if (doc.tags.indexOf(tag) > -1) {
+            _add = true;
+          }
+        });
+        if (_add) {
+          addRow(doc);
+        }
+      });
+    }
+    documentsTable.fnDraw();
+  }
+
+  function addRow(doc) {
+    try {
+      documentsTable.fnAddData([
+        getIcon(doc.contentType),
+        '<a href="' + doc.url + '" data-row-selector="true">' + doc.name + '</a>',
+        emptyStringIfNull(doc.description),
+        emptyStringIfNull(doc.tags.join("-")),
+        emptyStringIfNull(doc.owner),
+        emptyStringIfNull(doc.lastModified)
+      ], false);
+    }
+    catch (error) {
+      $(document).trigger("error", error);
+    }
+  }
+
+  function getIcon(contentType) {
+    var _code = '<img src="';
+    switch (contentType) {
+      case "workflow":
+        _code += '/oozie/static/art/icon_oozie_24_workflow.png';
+        break;
+      case "coordinator":
+        _code += '/oozie/static/art/icon_oozie_24_coordinator.png';
+        break;
+      case "bundle":
+        _code += '/oozie/static/art/icon_oozie_24_bundle.png';
+        break;
+    }
+    _code += '" />';
+    return _code;
+  }
+
+  function emptyStringIfNull(obj) {
+    if (obj != null && typeof obj != "undefined") {
+      return obj;
+    }
+    return "";
+  }
+</script>
+
 ${ commonfooter(messages) | n,unicode }
 ${ commonfooter(messages) | n,unicode }

+ 27 - 2
desktop/core/src/desktop/views.py

@@ -34,7 +34,7 @@ import django.views.debug
 
 
 from desktop.lib import django_mako
 from desktop.lib import django_mako
 from desktop.lib.conf import GLOBAL_CONFIG
 from desktop.lib.conf import GLOBAL_CONFIG
-from desktop.lib.django_util import login_notrequired, render_json, render
+from desktop.lib.django_util import login_notrequired, render_json, render, encode_json_for_js
 from desktop.lib.i18n import smart_str, force_unicode
 from desktop.lib.i18n import smart_str, force_unicode
 from desktop.lib.paths import get_desktop_root
 from desktop.lib.paths import get_desktop_root
 from desktop.log.access import access_log_level, access_warn
 from desktop.log.access import access_log_level, access_warn
@@ -43,17 +43,42 @@ from desktop import appmanager
 import desktop.conf
 import desktop.conf
 import desktop.log.log_buffer
 import desktop.log.log_buffer
 
 
+try:
+  import json
+except ImportError:
+  import simplejson as json
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 
 @access_log_level(logging.WARN)
 @access_log_level(logging.WARN)
 def home(request):
 def home(request):
+  docs = Document.objects.get_docs(request.user).order_by('-last_modified')[:100]
   return render('home.mako', request, {
   return render('home.mako', request, {
-    'documents': Document.objects.get_docs(request.user).order_by('-last_modified')[:100],
+    'documents': docs,
+    'json_documents': json.dumps(massaged_documents_for_json(docs)),
     'tags': DocumentTag.objects.filter(owner=request.user),
     'tags': DocumentTag.objects.filter(owner=request.user),
   })
   })
 
 
+def massaged_documents_for_json(documents):
+  docs = []
+  for doc in documents:
+    massaged_doc = {
+      'id': doc.id,
+      'contentType': doc.content_type.name,
+      'name': doc.name,
+      'url': doc.content_object.get_absolute_url(),
+      'description': doc.description,
+      'tags': ['%s' % (tag.tag) for tag in doc.tags.all()],
+      'owner': doc.owner.username,
+      'lastModified': doc.last_modified.strftime("%x %X"),
+      'lastModifiedInMillis': time.mktime(doc.last_modified.timetuple())
+    }
+    docs.append(massaged_doc)
+
+  return docs
+
 
 
 def add_or_create_tag(request):
 def add_or_create_tag(request):
   response = {'status': -1, 'message': ''}
   response = {'status': -1, 'message': ''}

+ 8 - 2
desktop/core/static/css/hue3.css

@@ -1418,6 +1418,12 @@ a#advanced-btn:hover {
 
 
 .navbar-fixed-top.nokids .navbar-inner {
 .navbar-fixed-top.nokids .navbar-inner {
   height: 45px;
   height: 45px;
-}#jHueTourVideoPlayer .modal-body {
-  max-height: 460px;
 }
 }
+
+a, a:hover, a:active, a:focus {
+  outline: 0;
+}
+
+#jHueTourVideoPlayer .modal-body {
+  max-height: 460px;
+}