浏览代码

HUE-3450 [metastore] Offer to edit table tags

Romain Rigaux 9 年之前
父节点
当前提交
2409a38

+ 49 - 1
apps/metastore/src/metastore/static/metastore/js/metastore.ko.js

@@ -88,7 +88,8 @@
             type: tableMeta.type,
             type: tableMeta.type,
             comment: tableMeta.comment,
             comment: tableMeta.comment,
             assistHelper: self.assistHelper,
             assistHelper: self.assistHelper,
-            i18n: self.i18n
+            i18n: self.i18n,
+            optimizerEnabled: optimizerEnabled
           })
           })
         }));
         }));
         self.loaded(true);
         self.loaded(true);
@@ -277,10 +278,12 @@
     self.database = options.database;
     self.database = options.database;
     self.assistHelper = options.assistHelper;
     self.assistHelper = options.assistHelper;
     self.i18n = options.i18n;
     self.i18n = options.i18n;
+    self.optimizerEnabled = options.optimizerEnabled;
     self.name = options.name;
     self.name = options.name;
     self.type = options.type;
     self.type = options.type;
 
 
     self.optimizerStats = ko.observable();
     self.optimizerStats = ko.observable();
+    self.navigatorStats = ko.observable();
 
 
     self.loaded = ko.observable(false);
     self.loaded = ko.observable(false);
     self.loading = ko.observable(false);
     self.loading = ko.observable(false);
@@ -301,6 +304,8 @@
     self.tableDetails = ko.observable();
     self.tableDetails = ko.observable();
     self.tableStats = ko.observable();
     self.tableStats = ko.observable();
     self.refreshingTableStats = ko.observable(false);
     self.refreshingTableStats = ko.observable(false);
+    self.showAddTagName = ko.observable(false);
+    self.addTagName = ko.observable('');
 
 
     //TODO: Fetch table comment async and don't set it from python
     //TODO: Fetch table comment async and don't set it from python
     self.comment = ko.observable(options.comment);
     self.comment = ko.observable(options.comment);
@@ -384,6 +389,21 @@
               self.partitions.loading(false);
               self.partitions.loading(false);
               self.partitions.loaded(true);
               self.partitions.loaded(true);
             }
             }
+            if (self.optimizerEnabled) {
+                $.get('/metadata/api/navigator/find_entity', {
+                  type: 'table',
+                  database: self.database.name,
+                  name: self.name
+                }, function(data){
+                  if (data && data.status == 0) {
+                    self.navigatorStats(ko.mapping.fromJS(data.entity));
+                  } else {
+                    $(document).trigger("info", data.message);
+                  }
+                }).fail(function (xhr, textStatus, errorThrown) {
+                  $(document).trigger("error", xhr.responseText);
+                });
+            }
           }
           }
           else {
           else {
             self.refreshingTableStats(false);
             self.refreshingTableStats(false);
@@ -397,6 +417,34 @@
         }
         }
       })
       })
     }
     }
+
+    self.addTags = function () {
+      $.post('/metadata/api/navigator/add_tags', {
+        id: ko.mapping.toJSON(self.navigatorStats().identity),
+        tags: ko.mapping.toJSON([self.addTagName()])
+      }, function(data) {
+        if (data && data.status == 0) {
+          self.navigatorStats().tags.push(self.addTagName());
+          self.addTagName('');
+          self.showAddTagName(false);
+        } else {
+          $(document).trigger("error", data.message);
+        }
+      });
+    };
+    
+    self.deleteTags = function (tag) {console.log(tag);
+      $.post('/metadata/api/navigator/delete_tags', {
+        id: ko.mapping.toJSON(self.navigatorStats().identity),
+        tags: ko.mapping.toJSON([tag])
+      }, function(data) {
+        if (data && data.status == 0) {
+          self.navigatorStats().tags.remove(tag);
+        } else {
+          $(document).trigger("error", data.message);
+        }
+      });
+    };
   }
   }
 
 
   MetastoreTable.prototype.showImportData = function () {
   MetastoreTable.prototype.showImportData = function () {

+ 1 - 1
apps/metastore/src/metastore/templates/components.mako

@@ -33,7 +33,7 @@
             </ul>
             </ul>
             <div class="pull-right">
             <div class="pull-right">
               <a class="pointer" data-bind="click: function() { optimizerEnabled(! optimizerEnabled()); }">
               <a class="pointer" data-bind="click: function() { optimizerEnabled(! optimizerEnabled()); }">
-                <i class="fa" data-bind="css: {'fa-toggle-off': ! optimizerEnabled(), 'fa-toggle-on': optimizerEnabled() }" style="margin-top:15px"></i> Optimizer
+                <i class="fa" data-bind="css: {'fa-toggle-off': ! optimizerEnabled(), 'fa-toggle-on': optimizerEnabled() }" style="margin-top:15px"></i> Enrich
               </a>
               </a>
             </div>
             </div>
           </div>
           </div>

+ 44 - 31
apps/metastore/src/metastore/templates/metastore.mako

@@ -374,7 +374,7 @@ ${ assist.assistPanel() }
       </div>
       </div>
       <!-- /ko -->
       <!-- /ko -->
 
 
-      <!-- ko if: $root.optimizerEnabled() && $root.database().optimizerStats().length > 0 -->
+      <!-- ko if: $root.optimizerEnabled() && $root.database().optimizerStats() && $root.database().optimizerStats().length > 0 -->
       <div class="span4 tile chart-container">
       <div class="span4 tile chart-container">
         <h4>${ _('Popular tables') }</h4>
         <h4>${ _('Popular tables') }</h4>
 
 
@@ -420,7 +420,7 @@ ${ assist.assistPanel() }
           &nbsp;
           &nbsp;
           <button class="btn toolbarBtn" title="${_('View the selected table')}" data-bind="click: function () { location.href = $root.optimizerUrl() + 'optimizer/#/table/12'; }, disable: selectedTables().length !== 1">
           <button class="btn toolbarBtn" title="${_('View the selected table')}" data-bind="click: function () { location.href = $root.optimizerUrl() + 'optimizer/#/table/12'; }, disable: selectedTables().length !== 1">
             <i class="fa fa-eye"></i> ${_('View in Optimizer')}
             <i class="fa fa-eye"></i> ${_('View in Optimizer')}
-          </button>          
+          </button>
           <!-- /ko -->
           <!-- /ko -->
         </div>
         </div>
 
 
@@ -549,10 +549,23 @@ ${ assist.assistPanel() }
     <div class="span3 tile">
     <div class="span3 tile">
       <!-- ko template: 'metastore-table-stats' --><!-- /ko -->
       <!-- ko template: 'metastore-table-stats' --><!-- /ko -->
     </div>
     </div>
-    <!-- ko if: $root.optimizerEnabled -->
+    <!-- ko if: $root.optimizerEnabled() && navigatorStats() -->
     <div class="span6 tile">
     <div class="span6 tile">
       <h4>${ _('Tagging') }</h4>
       <h4>${ _('Tagging') }</h4>
-      <div title="${ _('Tags') }"><i class="fa fa-fw fa-tags muted"></i> ${ _('No tags') }</div>
+      <div title="${ _('Tags') }"><i class="fa fa-fw fa-tags muted"></i>
+        <!-- ko foreach: navigatorStats().tags() -->
+          <span class="badge badge-info" data-bind="text: $data"></span><i class="fa fa-minus pointer" data-bind="click: $parent.deleteTags"></i>
+        <!-- /ko -->
+
+        <!-- ko if: navigatorStats().tags().length == 0 -->
+          ${ _('No tags') }
+        <!-- /ko -->
+        <div data-bind="visible: showAddTagName">
+          <input type="text" data-bind="value: addTagName, valueUpdate:'afterkeydown'">
+          <i class="fa fa-save pointer" data-bind="click: addTags, visible: addTagName" title="${ _('Save tag') }"></i>
+        </div>
+        <i class="fa fa-plus pointer" data-bind="click: function() { showAddTagName(true); }, visible: ! showAddTagName()" title="${ _('Add a tag') }"></i>
+      </div>
     </div>
     </div>
     <!-- /ko -->
     <!-- /ko -->
   </div>
   </div>
@@ -700,7 +713,7 @@ ${ assist.assistPanel() }
       <li><a href="#permissions" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-permissions'); }">${_('Permissions')}</a></li>
       <li><a href="#permissions" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-permissions'); }">${_('Permissions')}</a></li>
       <li><a href="#queries" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-queries'); }">${_('Queries')}</a></li>
       <li><a href="#queries" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-queries'); }">${_('Queries')}</a></li>
       <li><a href="#analysis" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-analysis'); }">${_('Analysis')}</a></li>
       <li><a href="#analysis" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-analysis'); }">${_('Analysis')}</a></li>
-      <li><a href="#lineage" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-lineage'); }">${_('Lineage')}</a></li>
+      <li><a href="#relationships" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-relationships'); }">${_('Relationships')}</a></li>
     <!-- /ko -->
     <!-- /ko -->
     <li><a href="#details" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-details'); }">${ _('Details') }</a></li>
     <li><a href="#details" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-details'); }">${ _('Details') }</a></li>
   </ul>
   </ul>
@@ -761,20 +774,20 @@ ${ assist.assistPanel() }
             <span style="display: none;">
             <span style="display: none;">
               <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
               <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
             </span>
             </span>
-      
+
           <i class="fa fa-long-arrow-right"></i> action=INSERT
           <i class="fa fa-long-arrow-right"></i> action=INSERT
       </div>
       </div>
 
 
       <div class="acl-block acl-block-airy">
       <div class="acl-block acl-block-airy">
         <span class="muted" title="3 months ago">TABLE</span>
         <span class="muted" title="3 months ago">TABLE</span>
-      
+
         <span>
         <span>
           <a class="muted" target="_blank" style="margin-left: 4px" title="Open in Sentry" href="/security/hive"><i class="fa fa-external-link"></i></a>
           <a class="muted" target="_blank" style="margin-left: 4px" title="Open in Sentry" href="/security/hive"><i class="fa fa-external-link"></i></a>
         </span>
         </span>
         <br>
         <br>
-      
+
         server=server1
         server=server1
-      
+
           <span>
           <span>
             <i class="fa fa-long-arrow-right"></i> db=<a class="pointer" title="Browse db privileges"><span data-bind="text: $root.database().name"></span></a>
             <i class="fa fa-long-arrow-right"></i> db=<a class="pointer" title="Browse db privileges"><span data-bind="text: $root.database().name"></span></a>
           </span>
           </span>
@@ -784,7 +797,7 @@ ${ assist.assistPanel() }
           <span style="display: none;">
           <span style="display: none;">
             <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
             <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
           </span>
           </span>
-      
+
           <i class="fa fa-long-arrow-right"></i> action=<span>SELECT</span>
           <i class="fa fa-long-arrow-right"></i> action=<span>SELECT</span>
       </div>
       </div>
     </div>
     </div>
@@ -794,21 +807,21 @@ ${ assist.assistPanel() }
       <span class="pointer" title="Undo" style="display: none;"> &nbsp; <i class="fa fa-undo"></i></span>
       <span class="pointer" title="Undo" style="display: none;"> &nbsp; <i class="fa fa-undo"></i></span>
       <span class="pointer" title="Save" style="display: none;"> &nbsp; <i class="fa fa-save"></i></span>
       <span class="pointer" title="Save" style="display: none;"> &nbsp; <i class="fa fa-save"></i></span>
     </div>
     </div>
- 
+
     <div class="acl-block-title">
     <div class="acl-block-title">
       <i class="fa fa-cube muted"></i> <a class="pointer"><span>customerAccess</span></a>
       <i class="fa fa-cube muted"></i> <a class="pointer"><span>customerAccess</span></a>
     </div>
     </div>
     <div>
     <div>
       <div class="acl-block acl-block-airy">
       <div class="acl-block acl-block-airy">
         <span class="muted" title="3 months ago">TABLE</span>
         <span class="muted" title="3 months ago">TABLE</span>
-    
+
         <span>
         <span>
           <a class="muted" target="_blank" style="margin-left: 4px" title="Open in Sentry" href="/security/hive"><i class="fa fa-external-link"></i></a>
           <a class="muted" target="_blank" style="margin-left: 4px" title="Open in Sentry" href="/security/hive"><i class="fa fa-external-link"></i></a>
         </span>
         </span>
         <br>
         <br>
-    
+
         server=server1
         server=server1
-    
+
           <span>
           <span>
             <i class="fa fa-long-arrow-right"></i> db=<a class="pointer" title="Browse db privileges"><span data-bind="text: $root.database().name"></span></a>
             <i class="fa fa-long-arrow-right"></i> db=<a class="pointer" title="Browse db privileges"><span data-bind="text: $root.database().name"></span></a>
           </span>
           </span>
@@ -818,7 +831,7 @@ ${ assist.assistPanel() }
           <span style="display: none;">
           <span style="display: none;">
             <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
             <i class="fa fa-long-arrow-right"></i> column=<a class="pointer" title="Browse column privileges"><span></span></a>
           </span>
           </span>
-    
+
         <i class="fa fa-long-arrow-right"></i> action=<span>ALL</span>
         <i class="fa fa-long-arrow-right"></i> action=<span>ALL</span>
       </div>
       </div>
       <div class="acl-block acl-actions">
       <div class="acl-block acl-actions">
@@ -829,27 +842,27 @@ ${ assist.assistPanel() }
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
-              
+
     <style>
     <style>
     .acl-panel {
     .acl-panel {
       border-left: 1px solid #e5e5e5;
       border-left: 1px solid #e5e5e5;
       padding-top: 6px;
       padding-top: 6px;
       padding-left: 12px;
       padding-left: 12px;
     }
     }
-    
+
     .acl-panel .nav-tabs {
     .acl-panel .nav-tabs {
       margin-bottom: 0;
       margin-bottom: 0;
     }
     }
-    
+
     .acl-panel h4:not(:first-child) {
     .acl-panel h4:not(:first-child) {
       margin-top: 20px;
       margin-top: 20px;
     }
     }
-    
+
     .acl-panel-content {
     .acl-panel-content {
       padding: 6px;
       padding: 6px;
       overflow-y: scroll;
       overflow-y: scroll;
     }
     }
-    
+
     .acl-block-title {
     .acl-block-title {
       background-color: #eeeeee;
       background-color: #eeeeee;
       font-weight: bold;
       font-weight: bold;
@@ -857,48 +870,48 @@ ${ assist.assistPanel() }
       margin-top: 14px;
       margin-top: 14px;
       margin-bottom: 4px;
       margin-bottom: 4px;
     }
     }
-    
+
     .acl-block {
     .acl-block {
       background-color: #f6f6f6;
       background-color: #f6f6f6;
       padding: 3px;
       padding: 3px;
       margin-bottom: 4px;
       margin-bottom: 4px;
     }
     }
-    
+
     .acl-block .checkbox, .acl-block .radio {
     .acl-block .checkbox, .acl-block .radio {
       margin-left: 6px;
       margin-left: 6px;
     }
     }
-    
+
     .acl-block-airy {
     .acl-block-airy {
       padding: 6px;
       padding: 6px;
     }
     }
-    
+
     .acl-block-airy input {
     .acl-block-airy input {
       margin-bottom: 0;
       margin-bottom: 0;
     }
     }
-    
+
     .acl-block-section {
     .acl-block-section {
       margin-top: 10px;
       margin-top: 10px;
     }
     }
-    
+
     .acl-block-section input {
     .acl-block-section input {
       margin-left: 14px;
       margin-left: 14px;
     }
     }
-    
+
     .span6 .acl-block input[type='text'] {
     .span6 .acl-block input[type='text'] {
       width: 25%;
       width: 25%;
     }
     }
-    
+
     .span6 .acl-block input[type='text'] {
     .span6 .acl-block input[type='text'] {
       width: 21%;
       width: 21%;
     }
     }
-    
+
     .acl-actions {
     .acl-actions {
       padding: 5px;
       padding: 5px;
       text-align: center;
       text-align: center;
       color: #CCC;
       color: #CCC;
       font-size: 20px;
       font-size: 20px;
     }
     }
-    
+
     .acl-actions span:hover {
     .acl-actions span:hover {
       color: #999;
       color: #999;
     }
     }
@@ -915,7 +928,7 @@ ${ assist.assistPanel() }
       <div class="empty-message">${ _('Currently not available.') }</div>
       <div class="empty-message">${ _('Currently not available.') }</div>
     </div>
     </div>
 
 
-    <div class="tab-pane" id="lineage">
+    <div class="tab-pane" id="relationships">
       <div class="empty-message">${ _('Currently not available.') }</div>
       <div class="empty-message">${ _('Currently not available.') }</div>
     </div>
     </div>
 
 

+ 16 - 4
desktop/libs/metadata/src/metadata/navigator_api.py

@@ -44,12 +44,18 @@ def error_handler(view_fn):
     except Http404, e:
     except Http404, e:
       raise e
       raise e
     except Exception, e:
     except Exception, e:
-      LOG.exception(str(e))
+      status = 500
+      message = str(e)
+      LOG.exception(message)
+
+      if 'Could not find' in message:
+        status = 200
+
       response = {
       response = {
         'status': -1,
         'status': -1,
-        'message': force_unicode(str(e))
+        'message': force_unicode(message)
       }
       }
-    return JsonResponse(response, status=500)
+    return JsonResponse(response, status=status)
   return decorator
   return decorator
 
 
 
 
@@ -117,6 +123,10 @@ def find_entity(request):
   else:
   else:
     raise MetadataApiException("type %s is unrecognized" % entity_type)
     raise MetadataApiException("type %s is unrecognized" % entity_type)
 
 
+  # Prevent nulls later
+  if 'tag' in response['entity'] and not response['entity']['tags']:
+    response['entity']['tags'] = []
+
   response['status'] = 0
   response['status'] = 0
   return JsonResponse(response)
   return JsonResponse(response)
 
 
@@ -131,7 +141,9 @@ def get_entity(request):
   if not entity_id:
   if not entity_id:
     raise MetadataApiException("get_entity requires an 'id' parameter")
     raise MetadataApiException("get_entity requires an 'id' parameter")
 
 
-  response['entity'] = api.get_entity(entity_id)
+  entity = api.get_entity(entity_id)
+
+  response['entity'] = entity
   response['status'] = 0
   response['status'] = 0
 
 
   return JsonResponse(response)
   return JsonResponse(response)