浏览代码

HUE-8155 [metastore] Improve the databases, tables and columns table in the Table Browser

This also removes the samples table for tables as the sample is now present in the column listing
Johan Ahlen 7 年之前
父节点
当前提交
4929c6da26
共有 46 个文件被更改,包括 488 次插入501 次删除
  1. 5 5
      apps/beeswax/src/beeswax/templates/list_designs.mako
  2. 4 4
      apps/beeswax/src/beeswax/templates/list_trashed_designs.mako
  3. 6 6
      apps/beeswax/src/beeswax/templates/my_queries.mako
  4. 2 2
      apps/filebrowser/src/filebrowser/templates/listdir_components.mako
  5. 2 2
      apps/hbase/src/hbase/templates/app.mako
  6. 4 4
      apps/jobbrowser/src/jobbrowser/templates/job_browser.mako
  7. 2 2
      apps/jobsub/src/jobsub/static/jobsub/templates/designs.html
  8. 2 2
      apps/jobsub/src/jobsub/templates/designs.mako
  9. 0 0
      apps/metastore/src/metastore/static/metastore/css/metastore.css
  10. 11 11
      apps/metastore/src/metastore/static/metastore/js/metastore.ko.js
  11. 12 59
      apps/metastore/src/metastore/static/metastore/js/metastore.model.js
  12. 19 0
      apps/metastore/src/metastore/static/metastore/less/metastore.less
  13. 62 230
      apps/metastore/src/metastore/templates/metastore.mako
  14. 2 2
      apps/oozie/src/oozie/templates/dashboard/list_oozie_bundles.mako
  15. 2 2
      apps/oozie/src/oozie/templates/dashboard/list_oozie_coordinator.mako
  16. 2 2
      apps/oozie/src/oozie/templates/dashboard/list_oozie_coordinators.mako
  17. 4 4
      apps/oozie/src/oozie/templates/dashboard/list_oozie_workflows.mako
  18. 8 8
      apps/oozie/src/oozie/templates/editor/list_bundles.mako
  19. 8 8
      apps/oozie/src/oozie/templates/editor/list_coordinators.mako
  20. 7 7
      apps/oozie/src/oozie/templates/editor/list_trashed_bundles.mako
  21. 7 7
      apps/oozie/src/oozie/templates/editor/list_trashed_coordinators.mako
  22. 7 7
      apps/oozie/src/oozie/templates/editor/list_trashed_workflows.mako
  23. 10 10
      apps/oozie/src/oozie/templates/editor/list_workflows.mako
  24. 2 2
      apps/oozie/src/oozie/templates/editor2/list_editor_bundles.mako
  25. 2 2
      apps/oozie/src/oozie/templates/editor2/list_editor_coordinators.mako
  26. 2 2
      apps/oozie/src/oozie/templates/editor2/list_editor_workflows.mako
  27. 7 7
      apps/oozie/src/oozie/templates/utils.inc.mako
  28. 2 2
      apps/pig/src/pig/templates/app.mako
  29. 2 2
      apps/security/src/security/templates/hive.mako
  30. 2 2
      apps/security/src/security/templates/sentry.mako
  31. 3 3
      apps/useradmin/src/useradmin/templates/list_groups.mako
  32. 3 3
      apps/useradmin/src/useradmin/templates/list_users.mako
  33. 0 0
      desktop/core/src/desktop/static/desktop/css/hue-embedded.css
  34. 0 0
      desktop/core/src/desktop/static/desktop/css/hue.css
  35. 0 0
      desktop/core/src/desktop/static/desktop/css/hue3-extra.css
  36. 1 1
      desktop/core/src/desktop/static/desktop/js/ko.editable.js
  37. 2 2
      desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js
  38. 79 0
      desktop/core/src/desktop/static/desktop/less/components/hue-catalog-entries-table.less
  39. 0 30
      desktop/core/src/desktop/static/desktop/less/components/hue-popover.less
  40. 18 16
      desktop/core/src/desktop/static/desktop/less/hue-cross-version.less
  41. 163 31
      desktop/core/src/desktop/templates/ko_components/ko_catalog_entries_table.mako
  42. 1 1
      desktop/core/src/desktop/templates/ko_components/ko_sql_columns_table.mako
  43. 3 3
      desktop/libs/dashboard/src/dashboard/templates/common_admin_collections.mako
  44. 2 2
      desktop/libs/indexer/src/indexer/templates/collections.mako
  45. 4 4
      desktop/libs/indexer/src/indexer/templates/indexes.mako
  46. 2 2
      desktop/libs/notebook/src/notebook/templates/notebooks.mako

+ 5 - 5
apps/beeswax/src/beeswax/templates/list_designs.mako

@@ -81,7 +81,7 @@ ${ layout.menubar(section='saved queries') }
     <table class="table table-condensed datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="savedCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="savedCheck"></div></th>
         <th>${_('Name')}</th>
         <th>${_('Description')}</th>
         <th>${_('Owner')}</th>
@@ -95,7 +95,7 @@ ${ layout.menubar(section='saved queries') }
         %>
       <tr>
         <td data-row-selector-exclude="true">
-          <div class="hueCheckbox savedCheck fa"
+          <div class="hue-checkbox savedCheck fa"
               data-edit-url="${ url(app_name + ':execute_design', design_id=design.id) }"
               data-history-url="${ url(app_name + ':list_query_history') }?q-design_id=${design.id}"
             % if may_edit:
@@ -204,7 +204,7 @@ ${ layout.menubar(section='saved queries') }
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
 
-      var selector = $(".hueCheckbox[checked='checked']:not(.selectAll)");
+      var selector = $(".hue-checkbox[checked='checked']:not(.selectAll)");
       if (selector.length == 1) {
         if (selector.data("edit-url")) {
           $("#editBtn").removeAttr("disabled").click(function () {
@@ -223,7 +223,7 @@ ${ layout.menubar(section='saved queries') }
         }
       }
 
-      var can_delete = $(".hueCheckbox[checked='checked'][data-delete-name]");
+      var can_delete = $(".hue-checkbox[checked='checked'][data-delete-name]");
       if (can_delete.length > 0 && can_delete.length == selector.length) {
         $("#trashQueryBtn").removeAttr("disabled");
         $("#trashQueryCaretBtn").removeAttr("disabled");
@@ -232,7 +232,7 @@ ${ layout.menubar(section='saved queries') }
 
     function deleteQueries() {
       viewModel.chosenSavedQueries.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenSavedQueries.push($(this).data("delete-name"));
       });
 

+ 4 - 4
apps/beeswax/src/beeswax/templates/list_trashed_designs.mako

@@ -65,7 +65,7 @@ ${layout.menubar(section='saved queries')}
     <table class="table table-condensed datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="savedCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="savedCheck"></div></th>
         <th>${_('Name')}</th>
         <th>${_('Description')}</th>
         <th>${_('Owner')}</th>
@@ -79,7 +79,7 @@ ${layout.menubar(section='saved queries')}
         %>
       <tr>
         <td data-row-selector-exclude="true">
-          <div class="hueCheckbox savedCheck fa"
+          <div class="hue-checkbox savedCheck fa"
             % if may_edit:
               data-delete-id="${ design.id }"
             % endif
@@ -183,7 +183,7 @@ ${layout.menubar(section='saved queries')}
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
 
-      var selector = $(".hueCheckbox[checked='checked']");
+      var selector = $(".hue-checkbox[checked='checked']");
 
       if (selector.length >= 1) {
         $(".toolbarBtn").removeAttr("disabled");
@@ -192,7 +192,7 @@ ${layout.menubar(section='saved queries')}
 
     function restoreQuery() {
       viewModel.chosenSavedQueries.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenSavedQueries.push($(this).data("delete-id"));
       });
 

+ 6 - 6
apps/beeswax/src/beeswax/templates/my_queries.mako

@@ -80,7 +80,7 @@ ${layout.menubar(section='my queries')}
       <table id="recentSavedQueriesTable" class="table table-condensed datatables">
         <thead>
           <tr>
-            <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="savedCheck"></div></th>
+            <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="savedCheck"></div></th>
             <th>${_('Name')}</th>
             <th>${_('Desc')}</th>
             <th>${_('Last Modified')}</th>
@@ -90,7 +90,7 @@ ${layout.menubar(section='my queries')}
         % for design in q_page.object_list:
           <tr>
             <td data-row-selector-exclude="true">
-              <div class="hueCheckbox savedCheck fa canDelete"
+              <div class="hue-checkbox savedCheck fa canDelete"
                    data-edit-url="${ url(app_name + ':execute_design', design_id=design.id) }"
                    data-delete-name="${ design.id }"
                    data-history-url="${ url(app_name + ':list_query_history') }?q-design_id=${design.id}"
@@ -119,7 +119,7 @@ ${layout.menubar(section='my queries')}
       <table id="recentRunQueriesTable" class="table table-condensed datatables">
         <thead>
           <tr>
-            <th width="1%"><div class="hueCheckbox selectAll" data-selectables="runCheck"></div></th>
+            <th width="1%"><div class="hue-checkbox selectAll" data-selectables="runCheck"></div></th>
             <th>${_('Time')}</th>
             <th>${_('Name')}</th>
             <th>${_('Query')}</th>
@@ -133,7 +133,7 @@ ${layout.menubar(section='my queries')}
         %>
           <tr>
             <td width="1%" data-row-selector-exclude="true">
-              <div class="hueCheckbox runCheck fa"
+              <div class="hue-checkbox runCheck fa"
                 data-edit-url="${ url(app_name + ':execute_design', design_id=query.design.id) }"
                 % if qcontext and query.last_state != models.QueryHistory.STATE.expired.index:
                   data-view-url="${ url(app_name + ':watch_query_history', query_history_id=query.id) }?context=${qcontext|u}"
@@ -278,7 +278,7 @@ ${layout.menubar(section='my queries')}
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
 
-      var selector = $(".hueCheckbox[checked='checked']");
+      var selector = $(".hue-checkbox[checked='checked']");
       if (selector.length == 1) {
         if (selector.data("view-url")) {
           $("#viewBtn").removeAttr("disabled").click(function () {
@@ -321,7 +321,7 @@ ${layout.menubar(section='my queries')}
 
     function deleteQueries() {
       viewModel.chosenSavedQueries.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenSavedQueries.push($(this).data("delete-name"));
       });
 

+ 2 - 2
apps/filebrowser/src/filebrowser/templates/listdir_components.mako

@@ -45,7 +45,7 @@ from filebrowser.conf import ENABLE_EXTRACT_UPLOADED_ARCHIVE
   <table id="fileBrowserTable" class="table table-condensed table-huedatatable tablescroller-disable" data-bind="style: {'opacity': isLoading() ? '.5': '1'}">
     <thead>
       <tr>
-        <th class="sorting_disabled" width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th class="sorting_disabled" width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th class="sortable sorting" data-sort="type" width="1%" data-bind="click: sort">&nbsp;</th>
         <th class="sortable sorting_asc" data-sort="name" data-bind="click: sort">${_('Name')}</th>
         <th class="sortable sorting" data-sort="size" width="10%" data-bind="click: sort">${_('Size')}</th>
@@ -624,7 +624,7 @@ from filebrowser.conf import ENABLE_EXTRACT_UPLOADED_ARCHIVE
   <script id="fileTemplate" type="text/html">
     <tr class="row-animated" style="cursor: pointer" data-bind="drop: { enabled: name !== '.' && type !== 'file' && (!$root.isS3() || ($root.isS3() && !$root.isS3Root())), value: $data }, event: { mouseover: toggleHover, mouseout: toggleHover, contextmenu: showContextMenu }, click: $root.viewFile, css: { 'row-selected': selected(), 'row-highlighted': highlighted(), 'row-deleted': deleted() }">
       <td class="center" data-bind="click: handleSelect" style="cursor: default" data-bind="enabled: name !== '..' ">
-        <div data-bind="multiCheck: '#fileBrowserTable', visible: name != '..', css: { hueCheckbox: name != '..', 'fa': name != '..', 'fa-check': selected }"></div>
+        <div data-bind="multiCheck: '#fileBrowserTable', visible: name != '..', css: { 'hue-checkbox': name != '..', 'fa': name != '..', 'fa-check': selected }"></div>
       </td>
       <td class="left"><i data-bind="click: $root.viewFile, css: { 'fa': true,
        % if 'oozie' in apps:

+ 2 - 2
apps/hbase/src/hbase/templates/app.mako

@@ -47,7 +47,7 @@ ${ commonheader(None, "hbase", user, request) | n,unicode }
   <table data-datasource="${datasource}" class="table table-condensed datatables tablescroller-disable" style="padding-left: 0;padding-right: 0">
       <thead>
         <tr>
-          <th width="1%"><div data-bind="click: ${datasource}.toggleSelectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': ${datasource}.allVisibleSelected() }"></div></th>
+          <th width="1%"><div data-bind="click: ${datasource}.toggleSelectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': ${datasource}.allVisibleSelected() }"></div></th>
           <!-- ko foreach: ${datasource}.columns() -->
             <th data-bind="text:$data"></th> <!-- need to i18n first -->
           <!-- /ko -->
@@ -179,7 +179,7 @@ ${ commonheader(None, "hbase", user, request) | n,unicode }
 
     <script id="itemTemplate" type="text/html">
       <tr>
-        <td><div data-bind="click: $data.select, css: {hueCheckbox: true,'fa': true, 'fa-check':$data.isSelected}" data-row-selector-exclude="true"></div></td>
+        <td><div data-bind="click: $data.select, css: { 'hue-checkbox': true,'fa': true, 'fa-check':$data.isSelected}" data-row-selector-exclude="true"></div></td>
         <td width="90%"><a data-bind="text:$data.name,attr: {href: '#'+hbaseApp.cluster()+'/'+$data.name}" data-row-selector="true"></a></td>
         <td width="5%"><i data-bind="click: $data.toggle, css: {'fa': true, 'fa-check-square':$data.enabled, 'fa-square-o':$data.enabled != true}" data-row-selector-exclude="true"></i></td>
       </tr>

+ 4 - 4
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -196,7 +196,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
                 <table id="jobsTable" class="datatables table table-condensed status-border-container">
                   <thead>
                   <tr>
-                    <th width="1%" class="vertical-align-middle"><div class="select-all hueCheckbox fa" data-bind="hueCheckAll: { allValues: jobs.apps, selectedValues: jobs.selectedJobs }"></div></th>
+                    <th width="1%" class="vertical-align-middle"><div class="select-all hue-checkbox fa" data-bind="hueCheckAll: { allValues: jobs.apps, selectedValues: jobs.selectedJobs }"></div></th>
                     <th width="15%">${_('Id')}</th>
                     <th width="20%">${_('Name')}</th>
                     <th width="6%">${_('User')}</th>
@@ -211,7 +211,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
                   <tbody data-bind="foreach: jobs.apps">
                     <tr class="status-border pointer" data-bind="css: {'completed': apiStatus() == 'SUCCEEDED', 'running': isRunning(), 'failed': apiStatus() == 'FAILED'}, click: fetchJob">
                       <td data-bind="click: function() {}, clickBubble: false">
-                        <div class="hueCheckbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#jobsTable', value: $data, hueChecked: $parent.jobs.selectedJobs"></div>
+                        <div class="hue-checkbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#jobsTable', value: $data, hueChecked: $parent.jobs.selectedJobs"></div>
                       </td>
                       <td data-bind="text: id"></td>
                       <td data-bind="text: name"></td>
@@ -1594,7 +1594,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
           <table id="schedulesTable" class="datatables table table-condensed status-border-container">
             <thead>
             <tr>
-              <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
+              <th width="1%"><div class="select-all hue-checkbox fa"></div></th>
               <th>${_('Status')}</th>
               <th>${_('Title')}</th>
               <th>${_('type')}</th>
@@ -1610,7 +1610,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
             <tbody data-bind="foreach: apps">
               <tr class="status-border pointer" data-bind="css: {'completed': properties.status() == 'SUCCEEDED', 'running': ['RUNNING', 'FAILED', 'KILLED'].indexOf(properties.status()) != -1, 'failed': properties.status() == 'FAILED' || properties.status() == 'KILLED'}, click: function() {  if (properties.externalId() && properties.externalId() != '-') { $root.job().id(properties.externalId()); $root.job().fetchJob(); } }">
                 <td data-bind="click: function() {}, clickBubble: false">
-                  <div class="hueCheckbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#schedulesTable', value: $data, hueChecked: $parent.selectedJobs"></div>
+                  <div class="hue-checkbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#schedulesTable', value: $data, hueChecked: $parent.selectedJobs"></div>
                 </td>
                 <td data-bind="text: properties.status"></td>
                 <td data-bind="text: properties.title"></td>

+ 2 - 2
apps/jobsub/src/jobsub/static/jobsub/templates/designs.html

@@ -1,7 +1,7 @@
 <table class="table table-condensed datatables">
   <thead>
     <tr>
-      <th width="1%"><div class="hueCheckbox selectAll" data-selectables="savedCheck"></div></th>
+      <th width="1%"><div class="hue-checkbox selectAll" data-selectables="savedCheck"></div></th>
       <th>{{ name }}</th>
       <th>{{ description }}</th>
       <th>{{ owner }}</th>
@@ -13,7 +13,7 @@
   <tbody data-bind="foreach: designs">
     <tr data-bind="with: design">
       <td data-row-selector-exclude="true">
-        <div class="hueCheckbox savedCheck" data-row-selector-exclude="true"></div>
+        <div class="hue-checkbox savedCheck" data-row-selector-exclude="true"></div>
       </td>
       <td><a href="javascript:void(0);" data-row-selector="true" data-bind="text: name, click: function(data, event) {$root.selectByIndex.call($root, $index()); $root.showDesign.call($root, data, event);}"></a></td>
       <td data-bind="text: description"></td>

+ 2 - 2
apps/jobsub/src/jobsub/templates/designs.mako

@@ -160,7 +160,7 @@ ${ commonheader(None, "jobsub", user, request) | n,unicode }
       <thead>
         <tr>
           <th width="1%">
-            <div id="selectAll" data-bind="click: toggleSelectAll, css: {'hueCheckbox': true, 'fa': true, 'fa-check': allSelected}"></div>
+            <div id="selectAll" data-bind="click: toggleSelectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}"></div>
           </th>
           <th>${_('Name')}</th>
           <th>${_('Description')}</th>
@@ -188,7 +188,7 @@ ${ commonheader(None, "jobsub", user, request) | n,unicode }
 <script id="designTemplate" type="text/html">
   <tr style="cursor: pointer" data-bind="with: design">
     <td data-row-selector-exclude="true" data-bind="click: function(data, event) {$root.toggleSelect.call($root, $index());}" class="center" style="cursor: default">
-      <div class="hueCheckbox savedCheck" data-row-selector-exclude="true" data-bind="css: {'hueCheckbox': name != '..', 'fa': name != '..', 'fa-check': $parent.selected()}"></div>
+      <div class="hue-checkbox savedCheck" data-row-selector-exclude="true" data-bind="css: {'hue-checkbox': name != '..', 'fa': name != '..', 'fa-check': $parent.selected()}"></div>
     </td>
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + id() }, text: name"></td>
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + id() }, text: description"></td>

文件差异内容过多而无法显示
+ 0 - 0
apps/metastore/src/metastore/static/metastore/css/metastore.css


+ 11 - 11
apps/metastore/src/metastore/static/metastore/js/metastore.ko.js

@@ -61,19 +61,8 @@ var MetastoreViewModel = (function () {
 
     self.selectedDatabases = ko.observableArray();
 
-    self.databaseQuery = ko.observable('').extend({ rateLimit: 150 });
-
     self.currentTab = ko.observable('');
 
-    self.filteredDatabases = ko.pureComputed(function () {
-      if (self.databaseQuery() === '') {
-        return self.databases();
-      }
-      return self.databases().filter(function (database) {
-        return database.catalogEntry.name.toLowerCase().indexOf(self.databaseQuery().toLowerCase()) !== -1;
-      });
-    });
-
     self.database = ko.observable(null);
 
     self.loadDatabases();
@@ -194,6 +183,17 @@ var MetastoreViewModel = (function () {
     }
   }
 
+  MetastoreViewModel.prototype.onDatabaseClick = function (catalogEntry) {
+    var self = this;
+
+    self.databases().some(function (database) {
+      if (database.catalogEntry === catalogEntry) {
+        self.setDatabase(database, function() { huePubSub.publish('metastore.url.change') });
+        return true;
+      }
+    });
+  }
+
   var lastLoadDatabasesPromise = null;
 
   MetastoreViewModel.prototype.reload = function () {

+ 12 - 59
apps/metastore/src/metastore/static/metastore/js/metastore.model.js

@@ -49,35 +49,6 @@ var MetastoreDatabase = (function () {
 
     self.showAddTagName = ko.observable(false);
     self.addTagName = ko.observable('');
-    self.tableQuery = ko.observable('').extend({rateLimit: 150});
-
-    self.filteredTables = ko.computed(function () {
-      var returned = self.tables();
-      if (self.tableQuery() !== '') {
-        returned = self.tables().filter(function (table) {
-          return table.catalogEntry.name.toLowerCase().indexOf(self.tableQuery()) > -1
-            || (table.comment() && table.comment().toLowerCase().indexOf(self.tableQuery()) > -1);
-        });
-      }
-      return returned.sort(function (a, b) {
-        if (options.optimizerEnabled()) {
-          if (typeof a.optimizerStats() !== 'undefined' && a.optimizerStats() !== null) {
-            if (typeof b.optimizerStats() !== 'undefined' && b.optimizerStats() !== null) {
-              if (a.optimizerStats().popularity === b.optimizerStats().popularity) {
-                return a.catalogEntry.name.toLowerCase().localeCompare(b.catalogEntry.name.toLowerCase());
-              }
-              return  b.optimizerStats().popularity - a.optimizerStats().popularity;
-            }
-            return -1
-          }
-          if (typeof b.optimizerStats() !== 'undefined' && b.optimizerStats() !== null) {
-            return 1;
-          }
-        }
-
-        return a.catalogEntry.name.toLowerCase().localeCompare(b.catalogEntry.name.toLowerCase());
-      });
-    });
 
     self.selectedTables = ko.observableArray();
 
@@ -85,6 +56,16 @@ var MetastoreDatabase = (function () {
     self.table = ko.observable(null);
   }
 
+  MetastoreDatabase.prototype.onTableClick = function (catalogEntry) {
+    var self = this;
+    self.tables().some(function (table) {
+      if (table.catalogEntry === catalogEntry) {
+        self.setTable(table, function() { huePubSub.publish('metastore.url.change'); });
+        return true;
+      }
+    })
+  };
+
   MetastoreDatabase.prototype.reload = function () {
     var self = this;
     if (!self.loading()) {
@@ -372,25 +353,12 @@ var MetastoreTable = (function () {
     self.loadingDetails = ko.observable(false);
     self.loadingColumns = ko.observable(false);
 
-    self.columnQuery = ko.observable('').extend({ rateLimit: 150 });
     self.columns = ko.observableArray();
-    self.filteredColumns = ko.computed(function () {
-      var returned = self.columns();
-      if (self.columnQuery() !== '') {
-        returned = self.columns().filter(function (column) {
-          var entry = column.catalogEntry;
-          return entry.name.toLowerCase().indexOf(self.columnQuery().toLowerCase()) !== -1
-            || (entry.getType().toLowerCase().indexOf(self.columnQuery().toLowerCase()) !== -1)
-            || (column.comment() && column.comment().toLowerCase().indexOf(self.columnQuery().toLowerCase()) !== -1);
-        });
-      }
-      return returned;
-    });
 
-    self.favouriteColumns = ko.observableArray();
     self.samples = new MetastoreTableSamples({
       metastoreTable: self
     });
+
     self.partitions = new MetastoreTablePartitions({
       metastoreTable: self
     });
@@ -453,7 +421,6 @@ var MetastoreTable = (function () {
             table: self
           })
         }));
-        self.favouriteColumns(self.columns().slice(0, 5));
 
         self.catalogEntry.getNavOptMeta().done(function (navOptMeta) {
           self.optimizerDetails(navOptMeta);
@@ -463,30 +430,16 @@ var MetastoreTable = (function () {
             topColIndex[topCol.name] = topCol;
           });
 
-          var favorites = [];
-          var nonFavorites = [];
-          var keys = [];
           self.columns().forEach(function (column) {
-            if (column.catalogEntry.isPrimaryKey() || column.catalogEntry.isPartitionKey()) {
-              keys.push(column);
-            } else if (topColIndex[column.catalogEntry.name]) {
-              favorites.push(column);
+            if (topColIndex[column.catalogEntry.name]) {
               column.popularity(topColIndex[column.catalogEntry.name].score);
-            } else {
-              nonFavorites.push(column);
             }
           });
-          favorites.sort(function (colA, colB) {
-            return colB.popularity() - colA.popularity();
-          });
-
-          self.favouriteColumns(keys.concat(favorites).concat(nonFavorites).slice(0, 5));
         }).always(function () {
           self.loadingQueries(false);
         });
       }).fail(function () {
         self.columns([]);
-        self.favouriteColumns([]);
       }).always(function () {
         self.loadingColumns(false);
       });

+ 19 - 0
apps/metastore/src/metastore/static/metastore/less/metastore.less

@@ -25,6 +25,25 @@
     color: @cui-gray-400;
   }
 
+  .entries-table-container {
+    margin: 0 10px;
+    position:relative;
+
+    .entries-table-header {
+      margin-bottom: 15px;
+    }
+
+    .entries-table-no-header {
+      padding-top: 40px;
+    }
+
+    .actionbar-actions {
+      position:absolute;
+      right:0;
+      top: 0;
+    }
+  }
+
   .sidebar-nav {
     padding: 0;
   }

+ 62 - 230
apps/metastore/src/metastore/templates/metastore.mako

@@ -115,57 +115,6 @@ ${ components.menubar(is_embeddable) }
   </ul>
 </script>
 
-<script type="text/html" id="metastore-columns-table">
-  <div style="overflow-x: auto; overflow-y: hidden">
-    <table class="table table-condensed table-nowrap metastore-table">
-      <thead>
-      <tr>
-        <th width="2%">&nbsp;</th>
-        <th width="2%" class="no-sort">&nbsp;</th>
-        <th width="20%">${_('Name')}</th>
-        <th width="10%">${_('Type')}</th>
-        <th width="66%" class="metastore-description-col">${_('Description')}</th>
-      </tr>
-      </thead>
-      <tbody data-bind="hueach: { data: $data, itemHeight: 32, scrollable: '${ MAIN_SCROLLABLE }', scrollableOffset: 200, disableHueEachRowCount: 5, scrollUp: true}">
-        <tr>
-          <td data-bind="text: $index() + $indexOffset() + 1"></td>
-          <td><a class="blue" href="javascript:void(0)" data-bind="click: showContextPopover"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a></td>
-          <td title="${ _("Scroll to the column") }">
-            <!-- ko if: $root.database() && $root.database().table() && $root.database().table().samples && $root.database().table().samples.loading() -->
-            <span data-bind="text: catalogEntry.name"></span>
-            <!-- ko if: $root.optimizerEnabled() && popularity()  -->
-            &nbsp;<i class="fa fa-star-o" data-bind="attr: { 'title': '${_ko('Popularity')}' + ': ' + popularity() + '%' }, tooltip"></i>
-            <!-- /ko -->
-            <i class="fa fa-key" title="${ _("Primary key") }" data-bind="visible: catalogEntry.isPrimaryKey(), tooltip"></i>
-            <i class="fa fa-key" title="${ _("Partition key") }" data-bind="visible: catalogEntry.isPartitionKey(), tooltip"></i>
-            <!-- /ko -->
-            <!-- ko ifnot: $root.database() && $root.database().table() && $root.database().table().samples && $root.database().table().samples.loading() -->
-            <a href="javascript:void(0)" class="column-selector" data-bind="click: $root.scrollToColumn">
-              <span data-bind="text: catalogEntry.name"></span>
-              <!-- ko if: $root.optimizerEnabled() && popularity()  -->
-              &nbsp;<i class="fa fa-star-o" data-bind="attr: { 'title': '${_ko('Popularity')}' + ': ' + popularity() + '%' }, tooltip"></i>
-              <!-- /ko -->
-              <i class="fa fa-key" title="${ _("Primary key") }" data-bind="visible: catalogEntry.isPrimaryKey(), tooltip"></i>
-              <i class="fa fa-key" title="${ _("Partition key") }" data-bind="visible: catalogEntry.isPartitionKey(), tooltip"></i>
-            </a>
-            <!-- /ko -->
-          </td>
-          <td data-bind="text: catalogEntry.getType()"></td>
-          <td class="metastore-description-col" >
-            <!-- ko ifnot: table.isView() -->
-            <!-- ko template: 'metastore-td-description' --><!-- /ko -->
-            <!-- /ko -->
-            <!-- ko if: table.isView() -->
-              <span style="white-space: pre;" data-bind="text: comment"></span>
-            <!-- /ko -->
-          </td>
-        </tr>
-      </tbody>
-    </table>
-  </div>
-</script>
-
 <script type="text/html" id="metastore-partition-columns-table">
   <div style="overflow-x: auto; overflow-y: hidden">
     <table class="table table-condensed table-nowrap metastore-table">
@@ -199,7 +148,7 @@ ${ components.menubar(is_embeddable) }
             &nbsp;
             <!-- /ko -->
             <!-- ko if: $data.withDrop -->
-            <div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: $data.values, selectedValues: $data.selectedValues }"></div>
+            <div class="hue-checkbox fa" data-bind="hueCheckAll: { allValues: $data.values, selectedValues: $data.selectedValues }"></div>
             <!-- /ko -->
           </th>
           <th>${_('Values')}</th>
@@ -215,7 +164,7 @@ ${ components.menubar(is_embeddable) }
             <span data-bind="text: $index() + 1"></span>
           <!-- /ko -->
           <!-- ko if: $parent.withDrop -->
-          <div class="hueCheckbox fa" data-bind="multiCheck: '#partitionsTable', value: $data, hueChecked: $parent.selectedValues"></div>
+          <div class="hue-checkbox fa" data-bind="multiCheck: '#partitionsTable', value: $data, hueChecked: $parent.selectedValues"></div>
           <!-- /ko -->
         </td>
         <td title="${_('Query partition data')}">
@@ -390,76 +339,59 @@ ${ components.menubar(is_embeddable) }
 </script>
 
 <script type="text/html" id="metastore-databases">
-  <div class="actionbar-actions" data-bind="dockable: { scrollable: '${ MAIN_SCROLLABLE }', jumpCorrection: 5, topSnap: '${ TOP_SNAP }' }">
-    <input class="input-xlarge search-query margin-left-10" type="text" placeholder="${ _('Search for a database...') }" data-bind="clearable: databaseQuery, value: databaseQuery, valueUpdate: 'afterkeydown'"/>
-    % if has_write_access:
-      <button class="btn toolbarBtn margin-left-20" title="${_('Drop the selected databases')}" data-bind="click: function () { $('#dropDatabase').modal('show'); }, disable: selectedDatabases().length === 0"><i class="fa fa-times"></i>  ${_('Drop')}</button>
-      <div id="dropDatabase" class="modal hide fade">
-
-      % if is_embeddable:
-        <form action="/metastore/databases/drop" data-bind="submit: dropAndWatch" method="POST">
-          <input type="hidden" name="is_embeddable" value="true"/>
-          <input type="hidden" name="start_time" value=""/>
-          <input type="hidden" name="source_type" data-bind="value: $root.sourceType"/>
-      % else:
-        <form id="dropDatabaseForm" action="/metastore/databases/drop" method="POST">
-      % endif
-          ${ csrf_token(request) | n,unicode }
-          <div class="modal-header">
-            <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
-            <h2 id="dropDatabaseMessage" class="modal-title">${ _('Do you really want to delete the following database(s)?') }</h2>
-          </div>
-          <div class="modal-body">
-            <ul data-bind="foreach: selectedDatabases">
-              <li>
-                <span data-bind="text: catalogEntry.name"></span>
-                <!-- ko if: $data.tables().length > 0 -->
-                    (<span data-bind="text: $data.tables().length"></span> tables)
-                <!-- /ko -->
-              </li>
-            </ul>
-          </div>
-          <div class="modal-footer">
-            <div class="label label-important margin-top-5 pull-left">${ _('Warning: This will drop all tables and objects within the database.') }</div>
-            <input type="button" class="btn" data-dismiss="modal" value="${_('No')}">
-            <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
-          </div>
-          <!-- ko foreach: selectedDatabases -->
-          <input type="hidden" name="database_selection" data-bind="value: catalogEntry.name" />
-          <!-- /ko -->
-        </form>
-      </div>
+  <div class="entries-table-container">
+    <div class="actionbar-actions">
+      % if has_write_access:
+        <button class="btn toolbarBtn margin-left-20" title="${_('Drop the selected databases')}" data-bind="click: function () { $('#dropDatabase').modal('show'); }, disable: selectedDatabases().length === 0"><i class="fa fa-times"></i>  ${_('Drop')}</button>
+        <div id="dropDatabase" class="modal hide fade">
+
+        % if is_embeddable:
+          <form action="/metastore/databases/drop" data-bind="submit: dropAndWatch" method="POST">
+            <input type="hidden" name="is_embeddable" value="true"/>
+            <input type="hidden" name="start_time" value=""/>
+            <input type="hidden" name="source_type" data-bind="value: $root.sourceType"/>
+        % else:
+          <form id="dropDatabaseForm" action="/metastore/databases/drop" method="POST">
+        % endif
+            ${ csrf_token(request) | n,unicode }
+            <div class="modal-header">
+              <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
+              <h2 id="dropDatabaseMessage" class="modal-title">${ _('Do you really want to delete the following database(s)?') }</h2>
+            </div>
+            <div class="modal-body">
+              <ul data-bind="foreach: selectedDatabases">
+                <li>
+                  <span data-bind="text: catalogEntry.name"></span>
+                </li>
+              </ul>
+            </div>
+            <div class="modal-footer">
+              <div class="label label-important margin-top-5 pull-left">${ _('Warning: This will drop all tables and objects within the database.') }</div>
+              <input type="button" class="btn" data-dismiss="modal" value="${_('No')}">
+              <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
+            </div>
+            <!-- ko foreach: selectedDatabases -->
+            <input type="hidden" name="database_selection" data-bind="value: catalogEntry.name" />
+            <!-- /ko -->
+          </form>
+        </div>
 
-      % if is_embeddable:
-        <button href="javascript: void(0);" class="btn btn-default" data-bind="publish: { 'open.link': '${ url('indexer:importer_prefill', source_type='manual', target_type='database') }' }" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
-      % elif ENABLE_NEW_CREATE_TABLE.get():
-        <button class="btn btn-default" data-bind="attr: { 'href': '${ url('indexer:importer_prefill', source_type='manual', target_type='database') }' }" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
-      % else:
-        <button href="${ url('beeswax:create_database') }" class="btn btn-default" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+        % if is_embeddable:
+          <button href="javascript: void(0);" class="btn btn-default" data-bind="publish: { 'open.link': '${ url('indexer:importer_prefill', source_type='manual', target_type='database') }' }" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+        % elif ENABLE_NEW_CREATE_TABLE.get():
+          <button class="btn btn-default" data-bind="attr: { 'href': '${ url('indexer:importer_prefill', source_type='manual', target_type='database') }' }" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+        % else:
+          <button href="${ url('beeswax:create_database') }" class="btn btn-default" title="${_('Create a new database')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+        % endif
       % endif
-    % endif
+    </div>
+
+    <div class="entries-table-no-header">
+      <!-- ko if: catalogEntry() -->
+      <!-- ko component: { name: 'catalog-entries-list', params: { catalogEntry: catalogEntry(), contextPopoverEnabled: true, onClick: onDatabaseClick.bind($data), selectedEntries: selectedDatabases, editableDescriptions: /true/i.test('${ has_write_access }') } } --><!-- /ko -->
+      <!-- /ko -->
+    </div>
   </div>
-  <table id="databasesTable" class="table table-condensed datatables" style="margin-bottom: 10px" data-bind="visible: filteredDatabases().length > 0">
-    <thead>
-    <tr>
-      <th width="1%" style="text-align: center" class="vertical-align-middle"><div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: filteredDatabases, selectedValues: selectedDatabases }"></div></th>
-      <th>&nbsp;</th>
-      <th>${ _('Database Name') }</th>
-    </tr>
-    </thead>
-    <tbody data-bind="hueach: { data: filteredDatabases, itemHeight: 32, scrollable: '${ MAIN_SCROLLABLE }', scrollableOffset: 145, scrollUp: true }">
-    <tr>
-      <td width="1%" style="text-align: center">
-        <div class="hueCheckbox fa" data-bind="multiCheck: '#databasesTable', value: $data, hueChecked: $parent.selectedDatabases"></div>
-      </td>
-      <td width="1%"><a class="blue" href="javascript:void(0)" data-bind="click: showContextPopover"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a></td>
-      <td>
-        <a href="javascript: void(0);" data-bind="text: catalogEntry.name, click: function () { $parent.setDatabase($data, function() { huePubSub.publish('metastore.url.change'); }) }"></a>
-      </td>
-    </tr>
-    </tbody>
-  </table>
-  <span class="margin-left-10" data-bind="visible: filteredDatabases().length === 0" style="font-style: italic; display: none;">${_('No databases found')}</span>
 </script>
 
 <script type="text/html" id="metastore-td-description">
@@ -574,84 +506,27 @@ ${ components.menubar(is_embeddable) }
   </div>
 
   <div class="row-fluid">
-    <div class="span12 tile" style="margin: 0 10px;">
-      <h4>${ _('Tables') }</h4>
-      <div class="actionbar-actions" style="margin-top:5px;" data-bind="visible: tables().length > 0, dockable: { scrollable: '${ MAIN_SCROLLABLE }', jumpCorrection: 5, topSnap: '${ TOP_SNAP }' }">
-        <input class="input-xlarge search-query margin-left-10" type="text" placeholder="${ _('Search for a table...') }" data-bind="clearable: tableQuery, value: tableQuery, valueUpdate: 'afterkeydown'"/>
-        <button class="btn toolbarBtn margin-left-20" title="${_('Browse the selected table')}" data-bind="click: function () { setTable(selectedTables()[0]); selectedTables([]); }, disable: selectedTables().length !== 1"><i class="fa fa-eye"></i> ${_('View')}</button>
+    <div class="span12 tile entries-table-container">
+      <h4 class="entries-table-header">${ _('Tables') }</h4>
+      <div class="actionbar-actions" data-bind="visible: tables().length > 0">
+        <button class="btn toolbarBtn margin-left-20" title="${_('Browse the selected table')}" data-bind="click: function () { onTableClick(selectedTables()[0].catalogEntry); selectedTables([]); }, disable: selectedTables().length !== 1"><i class="fa fa-eye"></i> ${_('View')}</button>
         <button class="btn toolbarBtn" title="${_('Query the selected table')}" data-bind="click: function () { IS_HUE_4 ? queryAndWatch('/notebook/browse/' + selectedTables()[0].catalogEntry.path.join('/') + '/', $root.sourceType()) : location.href = '/notebook/browse/' + selectedTables()[0].catalogEntry.path.join('/'); }, disable: selectedTables().length !== 1">
           <i class="fa fa-play fa-fw"></i> ${_('Query')}
         </button>
         % if has_write_access:
           <button id="dropBtn" class="btn toolbarBtn" title="${_('Drop the selected tables')}" data-bind="click: function () { $('#dropTable').modal('show'); }, disable: selectedTables().length === 0"><i class="fa fa-times"></i>  ${_('Drop')}</button>
           % if is_embeddable:
-            <button href="javascript: void(0);" class="btn btn-default" data-bind="publish: { 'open.link': '${ url('indexer:importer_prefill', source_type='all', target_type='table') }' + database().catalogEntry.name }" title="${_('Create a new table')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+            <button href="javascript: void(0);" class="btn btn-default" data-bind="publish: { 'open.link': '${ url('indexer:importer_prefill', source_type='all', target_type='table') }' + catalogEntry.name }" title="${_('Create a new table')}"><i class="fa fa-plus"></i> ${_('New')}</button>
           % elif ENABLE_NEW_CREATE_TABLE.get():
-            <button class="btn btn-default" data-bind="attr: { 'href': '${ url('indexer:importer_prefill', source_type='all', target_type='table') }' + database().catalogEntry.name }" title="${_('Create a new table')}"><i class="fa fa-plus"></i> ${_('New')}</button>
+            <button class="btn btn-default" data-bind="attr: { 'href': '${ url('indexer:importer_prefill', source_type='all', target_type='table') }' + catalogEntry.name }" title="${_('Create a new table')}"><i class="fa fa-plus"></i> ${_('New')}</button>
           % else:
-            <button class="btn btn-default" data-bind="attr: { 'href': '/beeswax/create/import_wizard/' + database().catalogEntry.name }" title="${_('Create a new table from a file')}"><i class="fa fa-stack"></i> ${_('New from file')}</button>
-            <button class="btn btn-default" data-bind="attr: { 'href': '/beeswax/create/create_table/' + database().catalogEntry.name }" title="${_('Create a new table manually')}"><i class="fa fa-plus"></i> ${_('New manually')}</button>
+            <button class="btn btn-default" data-bind="attr: { 'href': '/beeswax/create/import_wizard/' + catalogEntry.name }" title="${_('Create a new table from a file')}"><i class="fa fa-stack"></i> ${_('New from file')}</button>
+            <button class="btn btn-default" data-bind="attr: { 'href': '/beeswax/create/create_table/' + catalogEntry.name }" title="${_('Create a new table manually')}"><i class="fa fa-plus"></i> ${_('New manually')}</button>
           % endif
         % endif
       </div>
 
-      <table id="tablesTable" class="table table-condensed table-nowrap" style="margin-bottom: 10px; width: 100%" data-bind="visible: filteredTables().length > 0">
-        <thead>
-        <tr>
-          <th width="1%" style="text-align: center" class="vertical-align-middle"><div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: filteredTables, selectedValues: selectedTables }"></div></th>
-          <th>&nbsp;</th>
-          <th width="20%">${ _('Name') }</th>
-          <th class="metastore-description-col" width="69%">${ _('Description') }</th>
-          <!-- ko if: $root.optimizerEnabled  -->
-          <th width="10%">${ _('Columns') }</th>
-          <!-- /ko -->
-        </tr>
-        </thead>
-        <tbody data-bind="hueach: { data: filteredTables, itemHeight: 32, scrollable: '${ MAIN_SCROLLABLE }', scrollableOffset: 277, scrollUp: true }">
-          <tr>
-            <td width="1%" style="text-align: center">
-              <div class="hueCheckbox fa" data-bind="multiCheck: '#tablesTable', value: $data, hueChecked: $parent.selectedTables"></div>
-            </td>
-            <td width="1%"><a class="blue" href="javascript:void(0)" data-bind="click: showContextPopover"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a></td>
-            <td>
-              <a class="tableLink" href="javascript:void(0);" data-bind="click: function() { $parent.setTable($data, function() { huePubSub.publish('metastore.url.change'); }) }">
-                <!-- ko ifnot: $root.optimizerEnabled && optimizerStats() -->
-                <!-- ko if: catalogEntry.isTable() -->
-                  <i class="fa fa-fw fa-table" title="${ _('Table') }"></i>
-                <!-- /ko -->
-                <!-- ko if: catalogEntry.isView() -->
-                  <i class="fa fa-fw fa-eye" title="${ _('View') }"></i>
-                <!-- /ko -->
-                <!-- /ko -->
-                <!-- ko if: $root.optimizerEnabled && optimizerStats() -->
-                <!-- ko if: optimizerStats().is_fact -->
-                  <i class="fa fa-fw fa-database" title="${ _('Fact table') }"></i>
-                <!-- /ko -->
-                <!-- ko ifnot: optimizerStats().is_fact -->
-                  <i class="fa fa-fw fa-calendar" title="${ _('Dimension table') }"></i>
-                <!-- /ko -->
-                <!-- /ko -->
-                <span data-bind="text: catalogEntry.name"></span>
-                <!-- ko if: $root.optimizerEnabled() && optimizerStats() && optimizerStats().popularity  -->
-              &nbsp;<i class="fa fa-star-o" data-bind="attr: { 'title': '${_ko('Popularity')}' + ': ' + optimizerStats().popularity + '%' }, tooltip"></i>
-                <!-- /ko -->
-              </a>
-            </td>
-            <td class="metastore-description-col" data-bind="attr: { title: hueUtils.html2text(commentWithoutNewLines()) }">
-              <!-- ko template: 'metastore-td-description' --><!-- /ko -->
-            </td>
-            <!-- ko if: $root.optimizerEnabled -->
-              <!-- ko if: optimizerStats() -->
-              <td data-bind="text: optimizerStats().column_count"></td>
-              <!-- /ko -->
-            <!-- ko ifnot: optimizerStats() -->
-              <td></td>
-            <!-- /ko -->
-            <!-- /ko -->
-          </tr>
-        </tbody>
-      </table>
-      <div data-bind="visible: filteredTables().length === 0, css: { 'margin-left-10': tables().length > 0 }" style="font-style: italic; display: none;">${_('No tables found.')}</div>
+      <!-- ko component: { name: 'catalog-entries-list', params: { catalogEntry: catalogEntry, contextPopoverEnabled: true, onClick: onTableClick.bind($data), selectedEntries: selectedTables, editableDescriptions: /true/i.test('${ has_write_access }') } } --><!-- /ko -->
     </div>
   </div>
 
@@ -718,36 +593,7 @@ ${ components.menubar(is_embeddable) }
 
   <div class="tile">
     <h4 style="margin-bottom: 5px;">${ _('Columns') } (<span data-bind="text: columns().length"></span>) <i data-bind="visible: loadingColumns" class="fa fa-spinner fa-spin" style="display: none;"></i></h4>
-    <!-- ko with: favouriteColumns -->
-    <!-- ko template: "metastore-columns-table" --><!-- /ko -->
-    <!-- /ko -->
-
-    <a href="javascript: void(0);" title="${_('View more...')}" class="metastore-view-more" data-bind="visible: columns().length > favouriteColumns().length, click: function() { $root.currentTab('columns'); $('.page-content').scrollTop(0); }">
-      ${_('View more...')}
-    </a>
-  </div>
-
-  <div class="tile">
-    <h4>${ _('Sample') } <i data-bind="visible: samples.loading" class='fa fa-spinner fa-spin' style="display: none;"></i></h4>
-    <!-- ko with: samples -->
-      <!-- ko if: loaded() && !hasErrors() -->
-        <!-- ko with: preview -->
-        <div style="overflow: auto">
-        <!-- ko template: { if: rows().length, name: 'metastore-samples-table' } --><!-- /ko -->
-        </div>
-        <a href="javascript: void(0);" title="${_('View more...')}" class="metastore-view-more" data-bind="visible: rows().length >= 3, click: function() { $root.currentTab('sample'); $('.page-content').scrollTop(0);  }"  style="display: none;">
-          ${_('View more...')}
-        </a>
-        <!-- /ko -->
-        <!-- ko if: metastoreTable.tableDetails() -->
-        <div data-bind="visible: !rows().length && metastoreTable.tableDetails().is_view" style="display: none;">${ _('The view does not contain any data.') }</div>
-        <div data-bind="visible: !rows().length && !metastoreTable.tableDetails().is_view" style="display: none;">${ _('The table does not contain any data.') }</div>
-        <!-- /ko -->
-      <!-- /ko -->
-      <!-- ko if: hasErrors() -->
-      <div>${ _('Could not load the sample, see the server log for details.') }</div>
-      <!-- /ko -->
-    <!-- /ko -->
+    <!-- ko component: { name: 'catalog-entries-list', params: { catalogEntry: catalogEntry, contextPopoverEnabled: true, editableDescriptions: /true/i.test('${ has_write_access }') } } --><!-- /ko -->
   </div>
 
   <div class="tile" data-bind="visible: tableDetails() && tableDetails().partition_keys.length" style="display: none;">
@@ -766,12 +612,6 @@ ${ components.menubar(is_embeddable) }
   </div>
 </script>
 
-<script type="text/html" id="metastore-columns-tab">
-  <!-- ko with: filteredColumns -->
-  <!-- ko template: "metastore-columns-table" --><!-- /ko -->
-  <!-- /ko -->
-</script>
-
 <script type="text/html" id="metastore-partitions-tab">
   <!-- ko with: partitions -->
   <div class="tile" data-bind="visible: true" style="display: none;">
@@ -1113,7 +953,6 @@ ${ components.menubar(is_embeddable) }
 
   <ul class="nav nav-tabs nav-tabs-border margin-top-10">
     <li data-bind="css: { 'active': $root.currentTab() === 'overview' }"><a href="javascript: void(0);" data-bind="click: function() { $root.currentTab('overview'); }">${_('Overview')}</a></li>
-    <li data-bind="css: { 'active': $root.currentTab() === 'columns' }"><a href="javascript: void(0);" data-bind="click: function() { $root.currentTab('columns'); }">${_('Columns')} (<span data-bind="text: columns().length"></span>)</a></li>
     <!-- ko if: tableDetails() && tableDetails().partition_keys.length -->
       <li data-bind="css: { 'active': $root.currentTab() === 'partitions' }"><a href="javascript: void(0);" data-bind="click: function() { $root.currentTab('partitions'); }">${_('Partitions')} (<span data-bind="text: partitionsCountLabel"></span>)</a></li>
     <!-- /ko -->
@@ -1137,13 +976,6 @@ ${ components.menubar(is_embeddable) }
         <!-- ko template: 'metastore-overview-tab' --><!-- /ko -->
       <!-- /ko -->
 
-      <!-- ko if: $root.currentTab() === 'columns' -->
-        <input class="input-xlarge search-query margin-left-10" type="text" placeholder="${ _('Search for a column...') }" data-bind="clearable: columnQuery, value: columnQuery, valueUpdate: 'afterkeydown'"/>
-        <div class="margin-top-10">
-        <!-- ko template: 'metastore-columns-tab' --><!-- /ko -->
-        </div>
-      <!-- /ko -->
-
       <!-- ko if: $root.currentTab() === 'partitions' -->
         <!-- ko template: 'metastore-partitions-tab' --><!-- /ko -->
       <!-- /ko -->

+ 2 - 2
apps/oozie/src/oozie/templates/dashboard/list_oozie_bundles.mako

@@ -66,7 +66,7 @@ ${layout.menubar(section='bundles', dashboard=True)}
     <table class="table table-condensed" id="running-table">
       <thead>
         <tr>
-          <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
+          <th width="1%"><div class="select-all hue-checkbox fa"></div></th>
           <th width="14%">${ _('Kickoff Time') }</th>
           <th width="10%">${ _('Status') }</th>
           <th width="20%">${ _('Name') }</th>
@@ -449,7 +449,7 @@ ${layout.menubar(section='bundles', dashboard=True)}
               if (['RUNNING', 'PREP', 'WAITING', 'SUSPENDED', 'PREPSUSPENDED', 'PREPPAUSED', 'PAUSED', 'STARTED', 'FINISHING'].indexOf(bundle.status) > -1) {
                 try {
                   runningTable.fnAddData([
-                    bundle.canEdit ? '<div class="hueCheckbox fa" data-row-selector-exclude="true"></div>' : '',
+                    bundle.canEdit ? '<div class="hue-checkbox fa" data-row-selector-exclude="true"></div>' : '',
                     '<span data-sort-value="'+ bundle.kickoffTimeInMillis +'" data-type="date">' + emptyStringIfNull(bundle.kickoffTime) + '</span>',
                     '<span class="' + bundle.statusClass + '" data-type="status">' + bundle.status + '</span>',
                     bundle.appName,

+ 2 - 2
apps/oozie/src/oozie/templates/dashboard/list_oozie_coordinator.mako

@@ -224,7 +224,7 @@ ${ layout.menubar(section='coordinators', dashboard=True) }
               <table class="table table-condensed margin-top-10">
                 <thead>
                 <tr>
-                  <th width="20"><div data-bind="click: selectAll, css: { 'fa-check': allSelected }" class="hueCheckbox fa"></div></th>
+                  <th width="20"><div data-bind="click: selectAll, css: { 'fa-check': allSelected }" class="hue-checkbox fa"></div></th>
                   <th width="200">${ _('Day') }</th>
                   <th>${ _('Warning message') }</th>
                 </tr>
@@ -257,7 +257,7 @@ ${ layout.menubar(section='coordinators', dashboard=True) }
 
             <script id="calendarTemplate" type="text/html">
               <tr data-bind="css: { disabled: url == '' }">
-                <td data-bind="click: handleSelect"><div data-bind="css: { 'fa-check': selected }" class="hueCheckbox fa"></div></td>
+                <td data-bind="click: handleSelect"><div data-bind="css: { 'fa-check': selected }" class="hue-checkbox fa"></div></td>
                 <td data-bind="css: { disabled: url == '' }">
                   <a data-bind="attr: {href: url != '' ? url : 'javascript:void(0)', title: url ? '' : '${ _ko('Workflow not available or instantiated yet') }' }, css: { disabled: url == '' }" data-row-selector="true">
                     <span data-bind="text: title, attr: {'class': statusClass, 'id': 'date-' + $index()}"></span>

+ 2 - 2
apps/oozie/src/oozie/templates/dashboard/list_oozie_coordinators.mako

@@ -66,7 +66,7 @@ ${layout.menubar(section='coordinators', dashboard=True)}
     <table class="table table-condensed" id="running-table">
       <thead>
         <tr>
-          <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
+          <th width="1%"><div class="select-all hue-checkbox fa"></div></th>
           <th width="11%">${ _('Next Submission') }</th>
           <th width="5%">${ _('Status') }</th>
           <th width="20%">${ _('Name') }</th>
@@ -499,7 +499,7 @@ ${layout.menubar(section='coordinators', dashboard=True)}
               if (['RUNNING', 'PREP', 'WAITING', 'SUSPENDED', 'PREPSUSPENDED', 'PREPPAUSED', 'PAUSED', 'STARTED', 'FINISHING'].indexOf(coord.status) > -1) {
                 try {
                   runningTable.fnAddData([
-                    coord.canEdit ? '<div class="hueCheckbox fa" data-row-selector-exclude="true"></div>' : '',
+                    coord.canEdit ? '<div class="hue-checkbox fa" data-row-selector-exclude="true"></div>' : '',
                     '<span data-sort-value="'+ coord.nextMaterializedTimeInMillis +'" data-type="date">' + emptyStringIfNull(coord.nextMaterializedTime) + '</span>',
                     '<span class="' + coord.statusClass + '" data-type="status">' + coord.status + '</span>',
                     coord.appName,

+ 4 - 4
apps/oozie/src/oozie/templates/dashboard/list_oozie_workflows.mako

@@ -72,7 +72,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
     <table class="table table-condensed" id="running-table">
       <thead>
         <tr>
-          <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
+          <th width="1%"><div class="select-all hue-checkbox fa"></div></th>
           <th width="14%">${ _('Submission') }</th>
           <th width="5%">${ _('Status') }</th>
           <th width="31%">${ _('Name') }</th>
@@ -374,7 +374,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
       completedTableOffset = 1;
 
       // Clear select-all
-      $(".hueCheckbox").removeClass("fa-check");
+      $(".hue-checkbox").removeClass("fa-check");
     }
 
     function drawTable() {
@@ -474,7 +474,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
 
           // Find previously selected jobs
           var _ids = [];
-          $(".hueCheckbox.fa-check:not(.select-all)").each(function(){
+          $(".hue-checkbox.fa-check:not(.select-all)").each(function(){
             _ids.push($(this).parents("tr").find("a[data-row-selector='true']").text());
           });
           runningTable.fnClearTable();
@@ -497,7 +497,7 @@ ${ layout.menubar(section='workflows', dashboard=True) }
             if (['RUNNING', 'PREP', 'WAITING', 'SUSPENDED', 'PREPSUSPENDED', 'PREPPAUSED', 'PAUSED', 'STARTED', 'FINISHING'].indexOf(wf.status) > -1) {
               try {
                 runningTable.fnAddData([
-                  wf.canEdit ? '<div class="hueCheckbox fa ' + checkboxSelected + '" data-row-selector-exclude="true"></div>':'',
+                  wf.canEdit ? '<div class="hue-checkbox fa ' + checkboxSelected + '" data-row-selector-exclude="true"></div>':'',
                   '<span data-sort-value="'+ wf.createdInMillis +'" data-type="date">' + emptyStringIfNull(wf.created) + '</span>',
                   '<span class="' + wf.statusClass + '" data-type="status">' + wf.status + '</span>',
                   wf.appName,

+ 8 - 8
apps/oozie/src/oozie/templates/editor/list_bundles.mako

@@ -68,7 +68,7 @@ ${ layout.menubar(section='bundles') }
   <table id="bundleTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="bundleCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="bundleCheck"></div></th>
         <th width="10%">${ _('Name') }</th>
         <th width="20%">${ _('Description') }</th>
         <th width="35%">${ _('Coordinators') }</th>
@@ -82,7 +82,7 @@ ${ layout.menubar(section='bundles') }
       % for bundle in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-            <div class="hueCheckbox bundleCheck fa" data-row-selector-exclude="true"
+            <div class="hue-checkbox bundleCheck fa" data-row-selector-exclude="true"
               % if bundle.can_read(user):
                   data-clone-url="${ url('oozie:clone_bundle', bundle=bundle.id) }"
                   data-submit-url="${ url('oozie:submit_bundle', bundle=bundle.id) }"
@@ -196,7 +196,7 @@ ${ layout.menubar(section='bundles') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox[checked='checked']:not(.selectAll)");
+      var selector = $(".hue-checkbox[checked='checked']:not(.selectAll)");
       if (selector.length == 1) {
         var action_buttons = [
           ['#submit-btn', 'data-submit-url'],
@@ -211,7 +211,7 @@ ${ layout.menubar(section='bundles') }
           }
         });
       }
-      var can_delete = $(".hueCheckbox[checked='checked'][data-delete-id]");
+      var can_delete = $(".hue-checkbox[checked='checked'][data-delete-id]");
       if (can_delete.length > 0 && can_delete.length == selector.length) {
         $("#trash-btn").removeAttr("disabled");
         $("#trash-btn-caret").removeAttr("disabled");
@@ -220,7 +220,7 @@ ${ layout.menubar(section='bundles') }
 
     $("#trash-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#trash-job").modal("show");
@@ -228,14 +228,14 @@ ${ layout.menubar(section='bundles') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#destroy-job").modal("show");
     });
 
     $("#submit-btn").click(function () {
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _action = _this.attr("data-submit-url");
       $.get(_action, function (response) {
           $("#submit-job-modal").html(response);
@@ -246,7 +246,7 @@ ${ layout.menubar(section='bundles') }
 
     $("#clone-btn").click(function (e) {
       viewModel.isLoading(true);
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _url = _this.attr("data-clone-url");
       $.post(_url, function (data) {
         window.location = data.url;

+ 8 - 8
apps/oozie/src/oozie/templates/editor/list_coordinators.mako

@@ -71,7 +71,7 @@ ${ layout.menubar(section='coordinators') }
   <table id="coordinatorTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="coordinatorCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="coordinatorCheck"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Workflow') }</th>
@@ -85,7 +85,7 @@ ${ layout.menubar(section='coordinators') }
       %for coordinator in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-            <div class="hueCheckbox coordinatorCheck fa" data-row-selector-exclude="true"
+            <div class="hue-checkbox coordinatorCheck fa" data-row-selector-exclude="true"
               % if coordinator.can_read(user):
                   data-clone-url="${ url('oozie:clone_coordinator', coordinator=coordinator.id) }"
                   data-submit-url="${ url('oozie:submit_coordinator', coordinator=coordinator.id) }"
@@ -200,7 +200,7 @@ ${ layout.menubar(section='coordinators') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox[checked='checked']:not(.selectAll)");
+      var selector = $(".hue-checkbox[checked='checked']:not(.selectAll)");
       if (selector.length == 1) {
         var action_buttons = [
           ['#submit-btn', 'data-submit-url'],
@@ -215,7 +215,7 @@ ${ layout.menubar(section='coordinators') }
           }
         });
       }
-      var can_delete = $(".hueCheckbox[checked='checked'][data-delete-id]");
+      var can_delete = $(".hue-checkbox[checked='checked'][data-delete-id]");
       if (can_delete.length > 0 && can_delete.length == selector.length) {
         $("#trash-btn").removeAttr("disabled");
         $("#trash-btn-caret").removeAttr("disabled");
@@ -224,7 +224,7 @@ ${ layout.menubar(section='coordinators') }
 
     $("#trash-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#trash-job").modal("show");
@@ -232,14 +232,14 @@ ${ layout.menubar(section='coordinators') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#destroy-job").modal("show");
     });
 
     $("#submit-btn").click(function () {
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _action = _this.attr("data-submit-url");
       $.get(_action, function (response) {
           $("#submit-job-modal").html(response);
@@ -258,7 +258,7 @@ ${ layout.menubar(section='coordinators') }
 
     $("#clone-btn").click(function (e) {
       viewModel.isLoading(true);
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _url = _this.attr("data-clone-url");
       $.post(_url, function (data) {
         window.location = data.url;

+ 7 - 7
apps/oozie/src/oozie/templates/editor/list_trashed_bundles.mako

@@ -54,7 +54,7 @@ ${ layout.menubar(section='bundles') }
   <table id="bundleTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="bundleCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="bundleCheck"></div></th>
         <th width="10%">${ _('Name') }</th>
         <th width="20%">${ _('Description') }</th>
         <th width="35%">${ _('Coordinators') }</th>
@@ -68,7 +68,7 @@ ${ layout.menubar(section='bundles') }
       % for bundle in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-            <div class="hueCheckbox bundleCheck fa" data-row-selector-exclude="true" data-bundle-id="${ bundle.id }"></div>
+            <div class="hue-checkbox bundleCheck fa" data-row-selector-exclude="true" data-bundle-id="${ bundle.id }"></div>
           </td>
           <td>${ bundle.name }</td>
           <td>${ bundle.description }</td>
@@ -181,8 +181,8 @@ ${ layout.menubar(section='bundles') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox[checked='checked']");
-      var can_write = $(".hueCheckbox[checked='checked'][data-bundle-id]");
+      var selector = $(".hue-checkbox[checked='checked']");
+      var can_write = $(".hue-checkbox[checked='checked'][data-bundle-id]");
       if (can_write.length >= 1 && can_write.length == selector.length) {
         $("#destroy-btn").removeAttr("disabled");
         $("#restore-btn").removeAttr("disabled");
@@ -191,7 +191,7 @@ ${ layout.menubar(section='bundles') }
 
     $("#purge-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox").each(function( index ) {
+      $(".hue-checkbox").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("bundle-id"));
       });
       $("#purge-job").modal("show");
@@ -199,7 +199,7 @@ ${ layout.menubar(section='bundles') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("bundle-id"));
       });
       $("#destroy-job").modal("show");
@@ -207,7 +207,7 @@ ${ layout.menubar(section='bundles') }
 
     $("#restore-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("bundle-id"));
       });
       $("#restore-job").modal("show");

+ 7 - 7
apps/oozie/src/oozie/templates/editor/list_trashed_coordinators.mako

@@ -57,7 +57,7 @@ ${ layout.menubar(section='coordinators') }
   <table id="coordinatorTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="coordinatorCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="coordinatorCheck"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Workflow') }</th>
@@ -71,7 +71,7 @@ ${ layout.menubar(section='coordinators') }
       %for coordinator in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-            <div class="hueCheckbox coordinatorCheck fa" data-row-selector-exclude="true" data-coordinator-id="${ coordinator.id }"></div>
+            <div class="hue-checkbox coordinatorCheck fa" data-row-selector-exclude="true" data-coordinator-id="${ coordinator.id }"></div>
           </td>
           <td>${ coordinator.name }</td>
           <td>${ coordinator.description }</td>
@@ -183,8 +183,8 @@ ${ layout.menubar(section='coordinators') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox[checked='checked']");
-      var can_write = $(".hueCheckbox[checked='checked'][data-coordinator-id]");
+      var selector = $(".hue-checkbox[checked='checked']");
+      var can_write = $(".hue-checkbox[checked='checked'][data-coordinator-id]");
       if (can_write.length >= 1 && can_write.length == selector.length) {
         $("#destroy-btn").removeAttr("disabled");
         $("#restore-btn").removeAttr("disabled");
@@ -193,7 +193,7 @@ ${ layout.menubar(section='coordinators') }
 
     $("#purge-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox").each(function( index ) {
+      $(".hue-checkbox").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("coordinator-id"));
       });
       $("#purge-job").modal("show");
@@ -201,7 +201,7 @@ ${ layout.menubar(section='coordinators') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("coordinator-id"));
       });
       $("#destroy-job").modal("show");
@@ -209,7 +209,7 @@ ${ layout.menubar(section='coordinators') }
 
     $("#restore-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("coordinator-id"));
       });
       $("#restore-job").modal("show");

+ 7 - 7
apps/oozie/src/oozie/templates/editor/list_trashed_workflows.mako

@@ -59,7 +59,7 @@ ${ layout.menubar(section='workflows') }
   <table id="workflowTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="workflowCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="workflowCheck"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Last Modified') }</th>
@@ -72,7 +72,7 @@ ${ layout.menubar(section='workflows') }
       % for workflow in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-             <div class="hueCheckbox workflowCheck fa" data-row-selector-exclude="true" data-workflow-id="${ workflow.id }"></div>
+             <div class="hue-checkbox workflowCheck fa" data-row-selector-exclude="true" data-workflow-id="${ workflow.id }"></div>
           </td>
           <td>
             ${ workflow.name }
@@ -182,8 +182,8 @@ ${ layout.menubar(section='workflows') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox.workflowCheck[checked='checked']");
-      var can_delete = $(".hueCheckbox.workflowCheck[checked='checked'][data-workflow-id]");
+      var selector = $(".hue-checkbox.workflowCheck[checked='checked']");
+      var can_delete = $(".hue-checkbox.workflowCheck[checked='checked'][data-workflow-id]");
       if (can_delete.length >= 1 && can_delete.length == selector.length) {
         $("#destroy-btn").removeAttr("disabled");
         $("#restore-btn").removeAttr("disabled");
@@ -192,7 +192,7 @@ ${ layout.menubar(section='workflows') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("workflow-id"));
       });
       $("#destroyWf").modal("show");
@@ -200,7 +200,7 @@ ${ layout.menubar(section='workflows') }
 
     $("#purge-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox").each(function( index ) {
+      $(".hue-checkbox").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("workflow-id"));
       });
       $("#purgeWfs").modal("show");
@@ -208,7 +208,7 @@ ${ layout.menubar(section='workflows') }
 
     $("#restore-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("workflow-id"));
       });
       $("#restoreWf").modal("show");

+ 10 - 10
apps/oozie/src/oozie/templates/editor/list_workflows.mako

@@ -71,7 +71,7 @@ ${ layout.menubar(section='workflows') }
   <table id="workflowTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div class="hueCheckbox selectAll fa" data-selectables="workflowCheck"></div></th>
+        <th width="1%"><div class="hue-checkbox selectAll fa" data-selectables="workflowCheck"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Last Modified') }</th>
@@ -84,7 +84,7 @@ ${ layout.menubar(section='workflows') }
       % for workflow in jobs:
         <tr>
           <td data-row-selector-exclude="true">
-             <div class="hueCheckbox workflowCheck fa" data-row-selector-exclude="true"
+             <div class="hue-checkbox workflowCheck fa" data-row-selector-exclude="true"
               % if workflow.can_read(user):
                   data-submit-url="${ url('oozie:submit_workflow', workflow=workflow.id) }"
                   data-schedule-url="${ url('oozie:schedule_workflow', workflow=workflow.id) }"
@@ -196,7 +196,7 @@ ${ layout.menubar(section='workflows') }
 
     function toggleActions() {
       $(".toolbarBtn").attr("disabled", "disabled");
-      var selector = $(".hueCheckbox[checked='checked']:not(.selectAll)");
+      var selector = $(".hue-checkbox[checked='checked']:not(.selectAll)");
       if (selector.length == 1) {
         var action_buttons = [
           ['#submit-btn', 'data-submit-url'],
@@ -212,7 +212,7 @@ ${ layout.menubar(section='workflows') }
           }
         });
       }
-      var can_delete = $(".hueCheckbox[checked='checked'][data-delete-id]");
+      var can_delete = $(".hue-checkbox[checked='checked'][data-delete-id]");
       if (can_delete.length > 0 && can_delete.length == selector.length) {
         $("#trash-btn").removeAttr("disabled");
         $("#trash-btn-caret").removeAttr("disabled");
@@ -221,7 +221,7 @@ ${ layout.menubar(section='workflows') }
 
     $("#trash-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#trashWf").modal("show");
@@ -229,14 +229,14 @@ ${ layout.menubar(section='workflows') }
 
     $("#destroy-btn").click(function (e) {
       viewModel.chosenJobs.removeAll();
-      $(".hueCheckbox[checked='checked']").each(function( index ) {
+      $(".hue-checkbox[checked='checked']").each(function( index ) {
         viewModel.chosenJobs.push($(this).data("delete-id"));
       });
       $("#destroyWf").modal("show");
     });
 
     $("#submit-btn").click(function () {
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _action = _this.attr("data-submit-url");
       $.get(_action, function (response) {
           $("#submit-wf-modal").html(response);
@@ -247,7 +247,7 @@ ${ layout.menubar(section='workflows') }
 
     $("#clone-btn").click(function (e) {
       viewModel.isLoading(true);
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _url = _this.attr("data-clone-url");
       $.post(_url, function (data) {
         window.location = data.url;
@@ -256,14 +256,14 @@ ${ layout.menubar(section='workflows') }
 
     $("#schedule-btn").click(function (e) {
       viewModel.isLoading(true);
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _url = _this.attr("data-schedule-url");
       window.location.replace(_url);
     });
 
     $("#export-btn").click(function (e) {
       viewModel.isLoading(true);
-      var _this = $(".hueCheckbox[checked='checked']");
+      var _this = $(".hue-checkbox[checked='checked']");
       var _url = _this.attr("data-export-url");
       window.location.replace(_url);
       window.setTimeout(function(){

+ 2 - 2
apps/oozie/src/oozie/templates/editor2/list_editor_bundles.mako

@@ -77,7 +77,7 @@ ${ layout.menubar(section='bundles', is_editor=True) }
   <table id="workflowTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Owner') }</th>
@@ -87,7 +87,7 @@ ${ layout.menubar(section='bundles', is_editor=True) }
     <tbody data-bind="foreach: { data: jobs }">
       <tr data-bind="attr: { 'oozie-data-id': id() }">
         <td data-bind="click: $root.handleSelect" class="center" style="cursor: default" data-row-selector-exclude="true">
-          <div data-bind="multiCheck: '#workflowTable', css: { 'hueCheckbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
+          <div data-bind="multiCheck: '#workflowTable', css: { 'hue-checkbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
           <!-- ko if: ! uuid() -->
             <a data-bind="attr: { 'href': '${ url('oozie:open_old_bundle') }?bundle=' + id() }" data-row-selector="true"></a>
           <!-- /ko -->

+ 2 - 2
apps/oozie/src/oozie/templates/editor2/list_editor_coordinators.mako

@@ -76,7 +76,7 @@ ${ layout.menubar(section='coordinators', is_editor=True) }
   <table id="workflowTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Owner') }</th>
@@ -86,7 +86,7 @@ ${ layout.menubar(section='coordinators', is_editor=True) }
     <tbody data-bind="foreach: { data: jobs }">
       <tr data-bind="attr: { 'oozie-data-id': id() }">
         <td data-bind="click: $root.handleSelect" class="center" style="cursor: default" data-row-selector-exclude="true">
-          <div data-bind="multiCheck: '#workflowTable', css: { 'hueCheckbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
+          <div data-bind="multiCheck: '#workflowTable', css: { 'hue-checkbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
           <!-- ko if: ! uuid() -->
             <a data-bind="attr: { 'href': '${ url('oozie:open_old_coordinator') }?coordinator=' + id() }" data-row-selector="true"></a>
           <!-- /ko -->

+ 2 - 2
apps/oozie/src/oozie/templates/editor2/list_editor_workflows.mako

@@ -76,7 +76,7 @@ ${ layout.menubar(section='workflows', is_editor=True) }
   <table id="workflowTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Owner') }</th>
@@ -86,7 +86,7 @@ ${ layout.menubar(section='workflows', is_editor=True) }
     <tbody data-bind="foreach: { data: jobs }">
       <tr data-bind="attr: { 'oozie-data-id': id() }">
         <td data-bind="click: $root.handleSelect" class="center" style="cursor: default" data-row-selector-exclude="true">
-          <div data-bind="multiCheck: '#workflowTable', css: { 'hueCheckbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
+          <div data-bind="multiCheck: '#workflowTable', css: { 'hue-checkbox': true, 'fa': true, 'fa-check': isSelected }" data-row-selector-exclude="true"></div>
           <!-- ko if: ! uuid() -->
             <a data-bind="attr: { 'href': '${ url('oozie:open_old_workflow') }?workflow=' + id() }" data-row-selector="true"></a>
           <!-- /ko -->

+ 7 - 7
apps/oozie/src/oozie/templates/utils.inc.mako

@@ -627,10 +627,10 @@ function renderCrons() {
     });
 
     function toggleBulkButtons() {
-      if ($(".hueCheckbox.fa-check:not(.select-all)").length > 0){
+      if ($(".hue-checkbox.fa-check:not(.select-all)").length > 0){
         var _allResume = true;
         var _allSuspended = true;
-        $(".hueCheckbox.fa-check:not(.select-all)").each(function(){
+        $(".hue-checkbox.fa-check:not(.select-all)").each(function(){
           if (['RUNNING', 'PREP', 'WAITING'].indexOf($(this).parents("tr").find(".label").text()) > -1){
             _allResume = false;
           }
@@ -668,7 +668,7 @@ function renderCrons() {
 
     function bulkOperation(what) {
       var _ids = [];
-      $(".hueCheckbox.fa-check:not(.select-all)").each(function(){
+      $(".hue-checkbox.fa-check:not(.select-all)").each(function(){
         _ids.push($(this).parents("tr").find("a[data-row-selector='true']").text());
       });
 
@@ -694,21 +694,21 @@ function renderCrons() {
           else {
             $.jHueNotify.info(_messages[what]);
           }
-          $(".hueCheckbox").removeClass("fa-check");
+          $(".hue-checkbox").removeClass("fa-check");
           toggleBulkButtons();
           $(".btn-toolbar").find(".loader").addClass("hide");
           $(".bulkToolbarBtn").show();
       });
     }
 
-    $(document).on("click", ".hueCheckbox", function(){
+    $(document).on("click", ".hue-checkbox", function(){
       var _check = $(this);
       if (_check.hasClass("select-all")){
         if (_check.hasClass("fa-check")){
-          $(".hueCheckbox").removeClass("fa-check");
+          $(".hue-checkbox").removeClass("fa-check");
         }
         else {
-          $(".hueCheckbox").addClass("fa-check");
+          $(".hue-checkbox").addClass("fa-check");
         }
       }
       else {

+ 2 - 2
apps/pig/src/pig/templates/app.mako

@@ -77,7 +77,7 @@ ${ commonheader(None, "pig", user, request) | n,unicode }
         <table class="table table-condensed tablescroller-disable" data-bind="visible: scripts().length > 0">
           <thead>
           <tr>
-            <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}"></div></th>
+            <th width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}"></div></th>
             <th width="20%">${_('Name')}</th>
             <th width="79%">${_('Script')}</th>
           </tr>
@@ -104,7 +104,7 @@ ${ commonheader(None, "pig", user, request) | n,unicode }
         <script id="scriptTemplate" type="text/html">
           <tr style="cursor: pointer" data-bind="event: { mouseover: toggleHover, mouseout: toggleHover}">
             <td class="center" data-bind="click: handleSelect" style="cursor: default">
-              <div data-bind="css: {hueCheckbox: true, 'fa': true, 'fa-check': selected}"></div>
+              <div data-bind="css: { 'hue-checkbox': true, 'fa': true, 'fa-check': selected}"></div>
             </td>
             <td data-bind="click: $root.confirmViewScript">
               <strong><a data-bind="click: $root.confirmViewScript, text: name, attr: { href: '#edit/' + id() }"></a></strong>

+ 2 - 2
apps/security/src/security/templates/hive.mako

@@ -288,7 +288,7 @@ ${ layout.menubar(section='hive1', is_embeddable=is_embeddable) }
           <table class="card-marginbottom" data-bind="visible: $root.roles().length > 0 && ! $root.isLoadingRoles()">
             <thead>
               <tr>
-                <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { hueCheckbox: true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
+                <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
                 <th width="2%"></th>
                 <th width="20%" style="text-align:left">${ _('Name') }</th>
                 <th width="74%" style="text-align:left">${ _('Groups') }</th>
@@ -298,7 +298,7 @@ ${ layout.menubar(section='hive1', is_embeddable=is_embeddable) }
             <tbody data-bind="foreach: $root.filteredRoles">
               <tr>
                 <td class="center" data-bind="click: handleSelect" style="cursor: default">
-                  <div data-bind="css: { hueCheckbox: true, 'fa': true, 'fa-check': selected }"></div>
+                  <div data-bind="css: { 'hue-checkbox': true, 'fa': true, 'fa-check': selected }"></div>
                 </td>
                 <td class="center">
                   <a href="javascript:void(0);" title="${ _('Show privileges') }">

+ 2 - 2
apps/security/src/security/templates/sentry.mako

@@ -341,7 +341,7 @@ ${ layout.menubar(section=component, is_embeddable=is_embeddable) }
           <table class="card-marginbottom" data-bind="visible: $root.roles().length > 0 && ! $root.isLoadingRoles()">
             <thead>
               <tr>
-                <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { hueCheckbox: true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
+                <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
                 <th width="2%"></th>
                 <th width="20%" style="text-align:left">${ _('Name') }</th>
                 <th width="74%" style="text-align:left">${ _('Groups') }</th>
@@ -351,7 +351,7 @@ ${ layout.menubar(section=component, is_embeddable=is_embeddable) }
             <tbody data-bind="foreach: $root.filteredRoles">
               <tr>
                 <td class="center" data-bind="click: handleSelect" style="cursor: default">
-                  <div data-bind="css: { hueCheckbox: true, 'fa': true, 'fa-check': selected }"></div>
+                  <div data-bind="css: { 'hue-checkbox': true, 'fa': true, 'fa-check': selected }"></div>
                 </td>
                 <td class="center">
                   <a href="javascript:void(0);" title="${ _('Show privileges') }">

+ 3 - 3
apps/useradmin/src/useradmin/templates/list_groups.mako

@@ -64,7 +64,7 @@ ${layout.menubar(section='groups')}
       <tr>
         %if user.is_superuser:
             <th width="1%">
-              <div class="select-all hueCheckbox fa"></div>
+              <div class="select-all hue-checkbox fa"></div>
             </th>
         %endif
         <th>${_('Group Name')}</th>
@@ -78,7 +78,7 @@ ${layout.menubar(section='groups')}
               data-search="${group.name}${', '.join([group_user.username for group_user in group.user_set.all()])}">
           %if user.is_superuser:
             <td data-row-selector-exclude="true">
-              <div class="hueCheckbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
+              <div class="hue-checkbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
             </td>
           %endif
           <td>
@@ -225,7 +225,7 @@ ${layout.menubar(section='groups')}
     $groupsComponents.find(".delete-group-btn").click(function () {
       viewModel.chosenGroups.removeAll();
 
-      $groupsComponents.find(".hueCheckbox[checked='checked']").each(function (index) {
+      $groupsComponents.find(".hue-checkbox[checked='checked']").each(function (index) {
         viewModel.chosenGroups.push($(this).data("name").toString()); // needed for numeric group names
       });
 

+ 3 - 3
apps/useradmin/src/useradmin/templates/list_users.mako

@@ -68,7 +68,7 @@ ${layout.menubar(section='users')}
       <tr>
         %if user.is_superuser:
             <th width="1%">
-              <div class="select-all hueCheckbox fa"></div>
+              <div class="select-all hue-checkbox fa"></div>
             </th>
         %endif
         <th>${_('Username')}</th>
@@ -85,7 +85,7 @@ ${layout.menubar(section='users')}
               data-search="${listed_user.username}${listed_user.first_name}${listed_user.last_name}${listed_user.email}${', '.join([group.name for group in listed_user.groups.all()])}">
           %if user.is_superuser:
               <td data-row-selector-exclude="true">
-                <div class="hueCheckbox userCheck fa" data-row-selector-exclude="true" data-id="${ listed_user.id }"></div>
+                <div class="hue-checkbox userCheck fa" data-row-selector-exclude="true" data-id="${ listed_user.id }"></div>
               </td>
           %endif
           <td>
@@ -282,7 +282,7 @@ ${layout.menubar(section='users')}
     $usersComponents.find(".delete-user-btn").click(function () {
       viewModel.chosenUsers.removeAll();
 
-      $usersComponents.find(".hueCheckbox[checked='checked']").each(function (index) {
+      $usersComponents.find(".hue-checkbox[checked='checked']").each(function (index) {
         viewModel.chosenUsers.push($(this).data("id"));
       });
 

文件差异内容过多而无法显示
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue-embedded.css


文件差异内容过多而无法显示
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue.css


文件差异内容过多而无法显示
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue3-extra.css


+ 1 - 1
desktop/core/src/desktop/static/desktop/js/ko.editable.js

@@ -218,7 +218,7 @@
       }
 
       if (editableOptions.save) {
-        $editable.on('save', editableOptions.save);
+        $editable.on('save', editableOptions.save.bind(viewModel));
       }
 
       //setup observable to fire only when editable changes, not when options change

+ 2 - 2
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -1358,7 +1358,7 @@
           var insideGroup = false;
           var allCheckboxes = $container.find(":checkbox");
           if (allCheckboxes.length == 0) {
-            allCheckboxes = $container.find(".hueCheckbox");
+            allCheckboxes = $container.find(".hue-checkbox");
           }
           for (var i = 0; i < allCheckboxes.length; i++) {
             var checkbox = allCheckboxes[i];
@@ -5632,7 +5632,7 @@
     after: ['value', 'attr'],
     init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
       var value = valueAccessor();
-      $(element).addClass('hueCheckbox fa');
+      $(element).addClass('hue-checkbox fa');
 
       var updateCheckedState = function () {
         ko.utils.toggleDomNodeCssClass(element, 'fa-check', value());

+ 79 - 0
desktop/core/src/desktop/static/desktop/less/components/hue-catalog-entries-table.less

@@ -0,0 +1,79 @@
+/*
+ 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.
+*/
+
+.catalog-entries-list-container {
+  .flex(1 1 100%);
+  overflow: auto;
+
+  table .select-column {
+    text-align: center;
+    padding-top: 5px;
+    vertical-align: initial;
+  }
+
+  table td.name-column {
+    max-width: 130px;
+    width: 15%;
+    .nowrap-ellipsis();
+  }
+
+  table td.type-column {
+    max-width: 60px;
+    width: 5%;
+    .nowrap-ellipsis();
+  }
+
+  table td.comment-column {
+    max-width: 90px;
+    width: 20%;
+    .nowrap-ellipsis();
+  }
+
+  table td.sample-column {
+    width: 20%;
+    max-width: 400px;
+    .nowrap-ellipsis();
+    height: 24px;
+  }
+
+  .hue-catalog-entries-table-desc {
+    width: 100%;
+
+    .editable-container {
+      min-width: 90%;
+    }
+
+    .editable-inline-empty {
+      font-size: 13px;
+    }
+
+    .editable-input {
+      width: 100%;
+    }
+
+    .hue-catalog-entries-table-desc-input {
+      width: 100%;
+    }
+  }
+}
+
+.hue-popover {
+  .entries-table-description {
+    max-width: 400px;
+  }
+}

+ 0 - 30
desktop/core/src/desktop/static/desktop/less/components/hue-popover.less

@@ -420,36 +420,6 @@
   }
 }
 
-.catalog-entries-list-container {
-  .flex(1 1 100%);
-  overflow: auto;
-
-  table td.name-column {
-    max-width: 130px;
-    width: 15%;
-    .nowrap-ellipsis();
-  }
-
-  table td.type-column {
-    max-width: 60px;
-    width: 5%;
-    .nowrap-ellipsis();
-  }
-
-  table td.comment-column {
-    max-width: 90px;
-    width: 20%;
-    .nowrap-ellipsis();
-  }
-
-  table td.sample-column {
-    width: 20%;
-    max-width: 400px;
-    .nowrap-ellipsis();
-    height: 24px;
-  }
-}
-
 .context-popover-inner-content {
   position: absolute;
   .display-flex();

+ 18 - 16
desktop/core/src/desktop/static/desktop/less/hue-cross-version.less

@@ -19,6 +19,7 @@
 @import (reference) "hue-mixins.less";
 
 @import "components/hue-breadcrumbs.less";
+@import "components/hue-catalog-entries-table.less";
 @import "components/hue-demi-modal.less";
 @import "components/hue-filechooser.less";
 @import "components/hue-gridster.less";
@@ -140,7 +141,7 @@ input[type='password']::-ms-reveal {
 
 // Hue Checkbox
 
-.hueCheckbox {
+.hue-checkbox {
   width: 15px;
   height: 15px;
   border: 1px solid @cui-gray-400;
@@ -148,20 +149,25 @@ input[type='password']::-ms-reveal {
   padding: 0 !important;
   display: block !important;
   cursor: default;
-}
 
-.hueCheckbox.disabled {
-  border: 1px solid @cui-gray-300;
-  background-color: @cui-gray-050;
-  cursor: not-allowed;
-}
+  &.disabled {
+    border: 1px solid @cui-gray-300;
+    background-color: @cui-gray-050;
+    cursor: not-allowed;
+  }
 
-.hueCheckbox:hover {
-  border-color: @cui-gray-600;
-}
+  &:hover {
+    border-color: @cui-gray-600;
+  }
+
+  &.disabled:hover {
+    border-color: @cui-gray-300;
+  }
+
+  &.hide {
+    display: none!important;
+  }
 
-.hueCheckbox.disabled:hover {
-  border-color: @cui-gray-300;
 }
 
 .hueCheckboxText {
@@ -170,10 +176,6 @@ input[type='password']::-ms-reveal {
   top: -3px;
 }
 
-.hueCheckbox.hide {
-  display: none!important;
-}
-
 .hue-uncheck::before {
   line-height: 16px;
 }

+ 163 - 31
desktop/core/src/desktop/templates/ko_components/ko_catalog_entries_table.mako

@@ -22,9 +22,70 @@ from desktop.views import _ko
 
 <%def name="catalogEntriesTable()">
 
+  <script type="text/html" id="entries-table-td-description">
+    <td data-bind="attr: { 'title': comment }">
+    <!-- ko if: $parent.editableDescriptions -->
+      <div class="hue-catalog-entries-table-desc" data-bind="visibleOnHover: { selector: '.editable-inline-action' }">
+        <div data-bind="editable: comment, editableOptions: {
+          mode: 'inline',
+          enabled: true,
+          type: 'textarea',
+          showbuttons: 'bottom',
+          inputclass: 'hue-table-browser-desc-input',
+          toggle: 'manual',
+          toggleElement: '.toggle-editable',
+          placeholder: '${ _ko('Add a description...') }',
+          emptytext: '${ _ko('Add a description...') }',
+          inputclass: 'hue-catalog-entries-table-desc-input',
+          rows: 6,
+          save: saveComment,
+          inlineEditAction: { editClass: 'toggle-editable editable-inline-action' },
+          multiLineEllipsis: { overflowHeight: '40px', expandable: true, expandClass: 'editable-inline-action' }
+        }">${ _('Add a description...') }</div>
+      </div>
+    <!-- /ko -->
+    <!-- ko ifnot: $parent.editableDescriptions -->
+      <div class="entries-table-description" data-bind="text: comment, multiLineEllipsis"></div>
+    <!-- /ko -->
+    </td>
+  </script>
+
+  <script type="text/html" id="entries-table-tbody-no-entries">
+    <tbody>
+      <tr>
+        <td style="font-style: italic;" data-bind="attr: { 'colspan': colCount + (typeof $component.selectedEntries !== 'undefined' ? 1 : 0) + ($component.contextPopoverEnabled ? 1 : 0) }">
+          <!-- ko ifnot: hasErrors -->
+          ${ _("No entries found") }
+          <!-- /ko -->
+          <!-- ko if: hasErrors -->
+          ${ _("Error loading entries") }
+          <!-- /ko -->
+        </td>
+      </tr>
+    </tbody>
+  </script>
+
+  <script type="text/html" id="entries-table-shared-headers">
+    <!-- ko if: typeof selectedEntries !== 'undefined' -->
+    <th width="1%" class="select-column"><div class="hue-checkbox fa" data-bind="hueCheckAll: { allValues: filteredEntries, selectedValues: selectedEntries }"></div></th>
+    <!-- /ko -->
+    <!-- ko if: contextPopoverEnabled -->
+    <th width="1%">&nbsp;</th>
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="entries-table-shared-columns">
+    <!-- ko if: typeof $parent.selectedEntries !== 'undefined' -->
+    <td width="1%" class="select-column"><div class="hue-checkbox fa" data-bind="multiCheck: '#entryTable', value: $data, hueChecked: $parent.selectedEntries"></div></td>
+    <!-- /ko -->
+    <!-- ko if: $parent.contextPopoverEnabled -->
+    <td width="1%"><a href="javascript: void(0);" data-bind="click: showContextPopover"><i class="fa fa-info"></i></a></td>
+    <!-- /ko -->
+  </script>
+
   <script type="text/html" id="catalog-entries-list-template">
     <!-- ko if: !loading() -->
-    <div class="catalog-entries-list-filter context-popover-inline-autocomplete">
+    <div class="context-popover-inline-autocomplete">
       <!-- ko component: {
         name: 'inline-autocomplete',
         params: {
@@ -39,34 +100,50 @@ from desktop.views import _ko
 
     <div class="catalog-entries-list-container">
       <!-- ko hueSpinner: { spin: loading, center: true, size: 'xlarge' } --><!-- /ko -->
+      <!-- ko if: !loading() && catalogEntry.isSource() -->
+      <table id="entryTable" class="table table-condensed table-nowrap">
+        <thead>
+          <tr>
+            <!-- ko template: 'entries-table-shared-headers' --><!-- /ko -->
+            <th>${ _("Database") }</th>
+            <th>${ _("Description") } <!-- ko if: loadingNav --><i class="fa fa-spinner fa-spin"></i><!-- /ko --></th>
+          </tr>
+        </thead>
+        <!-- ko if: filteredEntries().length -->
+        <tbody data-bind="foreach: filteredEntries">
+          <tr data-bind="click: onRowClick">
+            <!-- ko template: 'entries-table-shared-columns' --><!-- /ko -->
+            <td><a href="javascript: void(0);" data-bind="text: catalogEntry.name, click: onClick, attr: { 'title': catalogEntry.getTitle() }"></a></td>
+            <!-- ko template: 'entries-table-td-description' --><!-- /ko -->
+          </tr>
+        </tbody>
+        <!-- /ko -->
+        <!-- ko if: filteredEntries().length === 0 -->
+        <!-- ko template: { name: 'entries-table-tbody-no-entries', data: { colCount: 2, hasErrors: hasErrors } } --><!-- /ko -->
+        <!-- /ko -->
+      </table>
+      <!-- /ko -->
 
       <!-- ko if: !loading() && catalogEntry.isDatabase() -->
-      <table class="table table-condensed table-nowrap">
+      <table id="entryTable" class="table table-condensed table-nowrap">
         <thead>
         <tr>
+          <!-- ko template: 'entries-table-shared-headers' --><!-- /ko -->
           <th data-bind="text: catalogEntry.getSourceType() !== 'solr' ? '${ _ko("Table") }' : '${ _ko("Collection") }'"></th>
           <th>${ _("Description") } <!-- ko if: loadingNav --><i class="fa fa-spinner fa-spin"></i><!-- /ko --></th>
         </tr>
         </thead>
         <!-- ko if: filteredEntries().length -->
         <tbody data-bind="foreach: filteredEntries">
-        <tr>
+        <tr data-bind="click: onRowClick">
+          <!-- ko template: 'entries-table-shared-columns' --><!-- /ko -->
           <td><a href="javascript: void(0);" data-bind="text: catalogEntry.name, click: onClick, attr: { 'title': catalogEntry.getTitle() }"></a></td>
-          <td data-bind="text: catalogEntry.getCommentObservable(), attr: { 'title': catalogEntry.getCommentObservable() }"></td>
+          <!-- ko template: 'entries-table-td-description' --><!-- /ko -->
         </tr>
         </tbody>
         <!-- /ko -->
         <!-- ko if: filteredEntries().length === 0 -->
-        <tbody>
-        <tr>
-          <!-- ko ifnot: hasErrors -->
-          <td colspan="2" style="font-style: italic;">${ _("No entries found") }</td>
-          <!-- /ko -->
-          <!-- ko if: hasErrors -->
-          <td colspan="2" style="font-style: italic;">${ _("Error loading entries") }</td>
-          <!-- /ko -->
-        </tr>
-        </tbody>
+        <!-- ko template: { name: 'entries-table-tbody-no-entries', data: { colCount: 2, hasErrors: hasErrors } } --><!-- /ko -->
         <!-- /ko -->
       </table>
       <!-- /ko -->
@@ -75,6 +152,7 @@ from desktop.views import _ko
       <table class="table table-condensed table-nowrap">
         <thead>
         <tr>
+          <!-- ko template: 'entries-table-shared-headers' --><!-- /ko -->
           <th><span data-bind="text: catalogEntry.getSourceType() !== 'solr' ? '${ _ko("Column") }' : '${ _ko("Field") }'"></span> (<span data-bind="text: filteredEntries().length"></span>)</th>
           <th>${ _("Type") }</th>
           <th>${ _("Description") } <!-- ko if: loadingNav --><i class="fa fa-spinner fa-spin"></i><!-- /ko --></th>
@@ -83,7 +161,8 @@ from desktop.views import _ko
         </thead>
         <!-- ko if: filteredEntries().length -->
         <tbody data-bind="foreach: filteredEntries">
-        <tr>
+        <tr data-bind="click: onRowClick">
+          <!-- ko template: 'entries-table-shared-columns' --><!-- /ko -->
           <td class="name-column" data-bind="attr: { 'title': catalogEntry.name + ' - ${ _ko("Click for more details") }' }">
             <a href="javascript: void(0);" data-bind="click: onClick">
               <span data-bind="text: catalogEntry.name"></span>
@@ -99,23 +178,14 @@ from desktop.views import _ko
             </a>
           </td>
           <td class="type-column" data-bind="text: catalogEntry.getType(), attr: { 'title': catalogEntry.getRawType() }"></td>
-          <td class="comment-column" data-bind="text: catalogEntry.getCommentObservable(), attr: { 'title': catalogEntry.getCommentObservable() }"></td>
+          <!-- ko template: 'entries-table-td-description' --><!-- /ko -->
           <td class="sample-column" data-bind="html: firstSample, attr: { 'title': hueUtils.html2text(firstSample()) }"></td>
           <td class="sample-column" data-bind="html: secondSample, attr: { 'title': hueUtils.html2text(secondSample()) }"></td>
         </tr>
         </tbody>
         <!-- /ko -->
         <!-- ko if: filteredEntries().length === 0 -->
-        <tbody>
-        <tr>
-          <!-- ko ifnot: hasErrors -->
-          <td colspan="5" style="font-style: italic;">${ _("No entries found") }</td>
-          <!-- /ko -->
-          <!-- ko if: hasErrors -->
-          <td colspan="5" style="font-style: italic;">${ _("Error loading entries") }</td>
-          <!-- /ko -->
-        </tr>
-        </tbody>
+        <!-- ko template: { name: 'entries-table-tbody-no-entries', data: { colCount: 5, hasErrors: hasErrors } } --><!-- /ko -->
         <!-- /ko -->
       </table>
       <!-- /ko -->
@@ -152,19 +222,53 @@ from desktop.views import _ko
   <script type="text/javascript">
     (function () {
 
-      function SampleEnrichedEntry(catalogEntry, onClick) {
+      function SampleEnrichedEntry(index, catalogEntry, onClick, onRowClick) {
         var self = this;
+        self.index = index;
         self.catalogEntry = catalogEntry;
-        self.popularity = ko.observable();
+        self.popularity = ko.observable(0);
         self.firstSample = ko.observable();
         self.secondSample = ko.observable();
         self.onClick = onClick;
+        self.onRowClick = onRowClick;
+        self.comment = self.catalogEntry.getCommentObservable();
       }
 
+      SampleEnrichedEntry.prototype.showContextPopover = function (entry, event) {
+        var $source = $(event.currentTarget || event.target);
+        var offset = $source.offset();
+        huePubSub.publish('context.popover.show', {
+          data: {
+            type: 'catalogEntry',
+            catalogEntry: entry.catalogEntry
+          },
+          orientation: 'right',
+          source: {
+            element: event.target,
+            left: offset.left,
+            top: offset.top - 2,
+            right: offset.left + $source.width() + 1,
+            bottom: offset.top + $source.height() - 2
+          }
+        });
+      };
+
+      SampleEnrichedEntry.prototype.saveComment = function () {
+        var self = this;
+        if (self.comment() !== self.catalogEntry.getResolvedComment()) {
+          self.catalogEntry.setComment(self.comment()).done(self.comment).fail(function () {
+            self.comment(self.catalogEntry.getResolvedComment());
+          })
+        }
+      };
+
       function CatalogEntriesList(params) {
         var self = this;
         self.catalogEntry = params.catalogEntry;
+        self.selectedEntries = params.selectedEntries;
         self.entries = ko.observableArray();
+        self.editableDescriptions = !!params.editableDescriptions;
+        self.contextPopoverEnabled = !!params.contextPopoverEnabled;
 
         // If the entry is a column without children
         self.columnSamples = ko.observableArray();
@@ -259,6 +363,19 @@ from desktop.views import _ko
 
         self.loading(true);
 
+        var entrySort = function (a, b) {
+          var aIsKey = a.catalogEntry.isPrimaryKey() || a.catalogEntry.isPartitionKey();
+          var bIsKey = b.catalogEntry.isPrimaryKey() || b.catalogEntry.isPartitionKey();
+          if (aIsKey && !bIsKey) {
+            return -1;
+          }
+          if (bIsKey && !aIsKey) {
+            return 1;
+          }
+
+          return (b.popularity() - a.popularity()) || (a.index - b.index);
+        };
+
         window.setTimeout(function () {
           if (self.catalogEntry.isField() && !self.catalogEntry.isComplex()) {
             self.cancellablePromises.push(self.catalogEntry.getSample({ silenceErrors: true, cancellable: true }).done(function (samples) {
@@ -271,11 +388,22 @@ from desktop.views import _ko
               self.loading(false);
             }));
           } else {
-            var onClick = function (sampleEnrichedEntry) {
-              params.onClick(sampleEnrichedEntry.catalogEntry);
+            var onClick = function (sampleEnrichedEntry, event) {
+              if (params.onClick) {
+                params.onClick(sampleEnrichedEntry.catalogEntry, event);
+              } else if (self.contextPopoverEnabled) {
+                sampleEnrichedEntry.showContextPopover(sampleEnrichedEntry, event);
+              }
+            };
+            var onRowClick = function (sampleEnrichedEntry, event) {;
+              if (self.selectedEntries && $(event.target).is('td')) {
+               $(event.currentTarget).find('.hue-checkbox').trigger('click');
+              }
             };
             var childPromise = self.catalogEntry.getChildren({ silenceErrors: true, cancellable: true }).done(function (childEntries) {
-              self.entries($.map(childEntries, function (entry) { return new SampleEnrichedEntry(entry, onClick) }));
+              var entries = $.map(childEntries, function (entry, index) { return new SampleEnrichedEntry(index, entry, onClick, onRowClick) });
+              entries.sort(entrySort);
+              self.entries(entries);
             }).fail(function () {
               self.hasErrors(true);
             }).always(function () {
@@ -307,9 +435,13 @@ from desktop.views import _ko
                       });
                     }
                   });
+                  var foundPopularEntries = popularityToApply.length !== 0;
                   while (popularityToApply.length) {
                     popularityToApply.pop()();
                   }
+                  if (foundPopularEntries) {
+                    self.entries().sort(entrySort);
+                  }
                 });
               }
             }));

+ 1 - 1
desktop/core/src/desktop/templates/ko_components/ko_sql_columns_table.mako

@@ -63,7 +63,7 @@ from desktop.views import _ko
             <!-- /ko -->
             <!-- ko if: typeof selected !== 'undefined' -->
             <td class="center" data-bind="multiCheckForeachVisible: { entries: $parent.filteredColumns, selectedAttr: 'selected' }" style="cursor: default;">
-              <div class="hueCheckbox fa" data-bind="css: {'fa-check': selected }"></div>
+              <div class="hue-checkbox fa" data-bind="css: {'fa-check': selected }"></div>
             </td>
 
             <!-- /ko -->

+ 3 - 3
desktop/libs/dashboard/src/dashboard/templates/common_admin_collections.mako

@@ -110,7 +110,7 @@
           <thead>
             <tr>
               <th style="width: 1%">
-                <span data-bind="click: toggleSelectAll, css: {'fa-check': ! ko.utils.arrayFilter(filteredCollections(), function(collection) {return !collection.selected()}).length}" class="hueCheckbox fa"></span>
+                <span data-bind="click: toggleSelectAll, css: {'fa-check': ! ko.utils.arrayFilter(filteredCollections(), function(collection) {return !collection.selected()}).length}" class="hue-checkbox fa"></span>
               </th>
               <th>${ _('Name') }</th>
               <th>${ _('Description') }</th>
@@ -120,7 +120,7 @@
           <tbody data-bind="foreach: filteredCollections">
             <tr>
               <td data-bind="click: $root.toggleCollectionSelect.bind($root), clickBubble: false">
-                <span data-bind="css: {'fa-check': $root.filteredCollections()[$index()].selected()}" class="hueCheckbox fa"></span>
+                <span data-bind="css: {'fa-check': $root.filteredCollections()[$index()].selected()}" class="hue-checkbox fa"></span>
               </td>
               <td><a data-bind="text: name, click: $root.editCollection" title="${ _('Click to edit') }" class="pointer"></a></td>
               <td><span data-bind="text: description"></span></td>
@@ -136,7 +136,7 @@
 <script id="importableTemplate" type="text/html">
   <tr>
     <td width="24">
-      <div data-bind="click: handleSelect, css: {hueCheckbox: true, 'fa': true, 'fa-check': selected}"></div>
+      <div data-bind="click: handleSelect, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': selected}"></div>
     </td>
     <td data-bind="text: name"></td>
   </tr>

+ 2 - 2
desktop/libs/indexer/src/indexer/templates/collections.mako

@@ -181,7 +181,7 @@ ${ commonheader(_('Search Indexes'), "indexer", user, request, "90px") | n,unico
             <thead>
               <tr>
                 <th>
-                  <span data-bind="click: toggleSelectAll, css: {'fa-check': !ko.utils.arrayFilter(displayCollections(), function(collection) {return !collection.selected()}).length}" class="hueCheckbox fa"></span>
+                  <span data-bind="click: toggleSelectAll, css: {'fa-check': !ko.utils.arrayFilter(displayCollections(), function(collection) {return !collection.selected()}).length}" class="hue-checkbox fa"></span>
                 </th>
                 <th width="60%">${_('Name')}</th>
                 <th width="40%">${_('Collections')}</th>
@@ -190,7 +190,7 @@ ${ commonheader(_('Search Indexes'), "indexer", user, request, "90px") | n,unico
             <tbody data-bind="foreach: displayCollections">
               <tr data-bind="routie: 'edit/' + name()" class="pointer">
                 <td data-bind="click: $parent.toggleCollectionSelect.bind($parent), clickBubble: false">
-                  <span data-bind="css: {'fa-check': $parent.displayCollections()[$index()].selected(), 'hueCheckbox fa': ! isAlias()}"></span>
+                  <span data-bind="css: {'fa-check': $parent.displayCollections()[$index()].selected(), 'hue-checkbox fa': ! isAlias()}"></span>
                 </td>
                 <td data-bind="text: name" style="cursor: pointer"></td>
                 <td data-bind="text: collections" style="cursor: pointer"></td>

+ 4 - 4
desktop/libs/indexer/src/indexer/templates/indexes.mako

@@ -227,7 +227,7 @@ ${ assist.assistPanel() }
                 <thead>
                   <tr>
                     <th style="width: 1%">
-                      <div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: alias.availableCollections, selectedValues: alias.chosenCollections }"></div>
+                      <div class="hue-checkbox fa" data-bind="hueCheckAll: { allValues: alias.availableCollections, selectedValues: alias.chosenCollections }"></div>
                     </th>
                     <th>${_('Collection')}</th>
                   </tr>
@@ -236,7 +236,7 @@ ${ assist.assistPanel() }
                 <!-- ko foreach: alias.availableCollections -->
                 <tr>
                   <td>
-                    <div class="hueCheckbox fa" data-bind="multiCheck: '#indexesChecksTable', value: $data, hueChecked: $parent.alias.chosenCollections"></div>
+                    <div class="hue-checkbox fa" data-bind="multiCheck: '#indexesChecksTable', value: $data, hueChecked: $parent.alias.chosenCollections"></div>
                   </td>
                   <td data-bind="text: name"></td>
                 </tr>
@@ -265,7 +265,7 @@ ${ assist.assistPanel() }
   <table class="table table-condensed datatables" id="list-indexes-table">
     <thead>
       <tr>
-        <th class="vertical-align-middle" width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th class="vertical-align-middle" width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Type') }</th>
         <th>${ _('Collections') }</th>
@@ -274,7 +274,7 @@ ${ assist.assistPanel() }
     <tbody data-bind="foreach: { data: filteredIndexes }">
       <tr>
         <td data-bind="click: $root.handleSelect" class="center" style="cursor: default">
-          <div data-bind="multiCheck: '#list-indexes-table', css: {'hueCheckbox': true, 'fa': true, 'fa-check': isSelected}"></div>
+          <div data-bind="multiCheck: '#list-indexes-table', css: { 'hue-checkbox': true, 'fa': true, 'fa-check': isSelected}"></div>
         </td>
         <td><a class="pointer" data-bind="text: name, click: function() { $root.fetchIndex($data); }"></a></td>
         <td data-bind="text: type"></td>

+ 2 - 2
desktop/libs/notebook/src/notebook/templates/notebooks.mako

@@ -104,7 +104,7 @@ ${ commonheader(_("Notebooks"), "spark", user, request, "60px") | n,unicode }
   <table id="notebookTable" class="table datatables">
     <thead>
       <tr>
-        <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
+        <th width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
         <th>${ _('Name') }</th>
         <th>${ _('Description') }</th>
         <th>${ _('Owner') }</th>
@@ -114,7 +114,7 @@ ${ commonheader(_("Notebooks"), "spark", user, request, "60px") | n,unicode }
     <tbody data-bind="foreach: { data: jobs }">
       <tr>
         <td data-bind="click: $root.handleSelect" class="center" style="cursor: default" data-row-selector-exclude="true">
-          <div class="hueCheckbox fa" data-bind="multiCheck: '#notebookTable', css: {'fa-check': isSelected }" data-row-selector-exclude="true"></div>
+          <div class="hue-checkbox fa" data-bind="multiCheck: '#notebookTable', css: {'fa-check': isSelected }" data-row-selector-exclude="true"></div>
           <a data-bind="attr: { 'href': absoluteUrl }" data-row-selector="true"></a>
         </td>
         <td data-bind="text: name"></td>

部分文件因为文件数量过多而无法显示