Просмотр исходного кода

HUE-9058 [assist] Add share to the doc assist right-click context menu

Johan Ahlen 6 лет назад
Родитель
Сommit
76d2fcdac1

+ 1 - 1
desktop/core/src/desktop/js/doc/hueFileEntry.js

@@ -376,7 +376,7 @@ class HueFileEntry {
     }
     if (this.selectedEntry()) {
       this.selectedEntry().loadDocument();
-      $('#shareDocumentModal').modal('show');
+      huePubSub.publish('doc.show.share.modal', this.selectedEntry());
     }
   }
 

+ 3 - 0
desktop/core/src/desktop/js/ko/components/assist/ko.assistDocumentsPanel.js

@@ -42,6 +42,9 @@ const TEMPLATE = `
       'Delete document'
     )}</a></li>
     <!-- /ko -->
+    <li><a href="javascript: void(0);" data-bind="publish: { 'doc.show.share.modal': $data }"><i class="fa fa-fw fa-users"></i> ${I18n(
+      'Share'
+    )}</a></li>
   </script>
   
   <script type="text/html" id="assist-document-header-actions">

+ 129 - 0
desktop/core/src/desktop/js/ko/components/ko.shareDocModal.js

@@ -0,0 +1,129 @@
+// 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.
+
+import $ from 'jquery';
+import ko from 'knockout';
+
+import componentUtils from './componentUtils';
+import huePubSub from 'utils/huePubSub';
+import I18n from 'utils/i18n';
+
+// prettier-ignore
+const TEMPLATE = `
+  <!-- ko with: document -->
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-label="${ I18n('Close') }"><span aria-hidden="true">&times;</span></button>
+    <h2 class="modal-title">${ I18n('Sharing') } - <span data-bind="text: $parent.definition().name"></span></h2>
+  </div>
+  <div class="modal-body" style="overflow: visible; height: 240px">
+    <!-- ko with: definition -->
+    <div class="row-fluid" data-bind="visible: !$parent.hasErrors()" style="max-height: 114px;" id="scrolldiv">
+      <div class="span6">
+        <h4 class="muted" style="margin-top: 0">${ I18n('Read') }</h4>
+        <div data-bind="visible: (perms.read.users.length == 0 && perms.read.groups.length == 0)">${ I18n('The document is not shared for read.') }</div>
+        <ul class="unstyled airy" data-bind="foreach: perms.read.users">
+          <li>
+            <span class="badge badge-info" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-user"></i> <span data-bind="text: $parents[1].prettifyUsernameById(id), attr:{'data-id': id}"></span></span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeUserReadShare($data) }"> <i class="fa fa-times"></i></span>
+          </li>
+        </ul>
+        <ul class="unstyled airy" data-bind="foreach: perms.read.groups">
+          <li>
+            <span class="badge badge-info" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-users"></i> ${ I18n('Group') } &quot;<span data-bind="text: name"></span>&quot;</span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeGroupReadShare($data) }"> <i class="fa fa-times"></i></span>
+          </li>
+        </ul>
+      </div>
+
+      <div class="span6">
+        <h4 class="muted" style="margin-top: 0">${ I18n('Modify') }</h4>
+        <div data-bind="visible: (perms.write.users.length == 0 && perms.write.groups.length == 0)">${ I18n('The document is not shared for modify.') }</div>
+        <ul class="unstyled airy" data-bind="foreach: perms.write.users">
+          <li>
+            <span class="badge badge-info badge-left" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-user"></i> <span data-bind="text: $parents[1].prettifyUsernameById(id), attr:{'data-id': id}"></span></span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeUserWriteShare($data) }"> <i class="fa fa-times"></i></span>
+          </li>
+        </ul>
+        <ul class="unstyled airy" data-bind="foreach: perms.write.groups">
+          <li>
+            <span class="badge badge-info badge-left" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-users"></i> ${ I18n('Group') } &quot;<span data-bind="text: name"></span>&quot;</span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeGroupWriteShare($data) }"> <i class="fa fa-times"></i></span>
+          </li>
+        </ul>
+      </div>
+    </div>
+    <!-- /ko -->
+    <div class="doc-browser-empty animated" style="display: none;" data-bind="visible: loading">
+      <i class="fa fa-spinner fa-spin fa-2x" style="color: #999;"></i>
+    </div>
+    <div class="doc-browser-empty animated" style="display: none;" data-bind="visible: hasErrors() && ! loading()">
+      ${ I18n('There was an error loading the document.')}
+    </div>
+    <div style="margin-top: 20px" data-bind="visible: fileEntry.canModify() && ! hasErrors() && ! loading()">
+      <div class="input-append" style="font-size: inherit">
+        <div id="menu"></div>
+        <input id="userSearchAutocomp" placeholder="${ I18n('Type a username or a group name') }" type="text" data-bind="
+            autocomplete: {
+              source: shareAutocompleteUserSource.bind($data),
+              itemTemplate: 'user-search-autocomp-item',
+              noMatchTemplate: 'user-search-autocomp-no-match',
+              valueObservable: searchInput,
+              showSpinner: true,
+              classPrefix: 'hue-',
+              onEnter: onShareAutocompleteUserEnter.bind($data),
+              appendTo: $('#menu')
+            }, 
+            clearable: {
+              value: searchInput,
+              textInput: searchInput
+            }
+          " class="ui-autocomplete-input" autocomplete="off" style="width: 420px">
+        <div class="btn-group" style="overflow:visible">
+          <a id="documentShareAddBtn" class="btn" data-bind="click: function () {  onShareAutocompleteUserEnter() }"><span data-bind="text: selectedPerm() == 'read' ? '${ I18n('Read') }' : '${ I18n('Modify') }'"></span></a>
+          <a id="documentShareCaret" class="btn dropdown-toggle" data-toggle="dropdown">
+           <span class="caret"></span>
+          </a>
+          <ul class="dropdown-menu">
+            <li><a data-bind="click: function () { selectedPerm('read'); onShareAutocompleteUserEnter() }" href="javascript:void(0)"><i class="fa fa-plus"></i> ${ I18n('Read') }</a></li>
+            <li><a data-bind="click: function () { selectedPerm('write'); onShareAutocompleteUserEnter() }" href="javascript:void(0)"><i class="fa fa-plus"></i> ${ I18n('Modify') }</a></li>
+          </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <a href="#" data-dismiss="modal" class="btn disable-feedback disable-enter">${ I18n('Close') }</a>
+  </div>
+  <!-- /ko -->
+`;
+
+componentUtils.registerComponent('share-doc-modal', undefined, TEMPLATE).then(() => {
+  huePubSub.subscribe('doc.show.share.modal', hueFileEntry => {
+    let $shareDocMocal = $('#shareDocModal');
+    if ($shareDocMocal.length) {
+      ko.cleanNode($shareDocMocal[0]);
+      $shareDocMocal.remove();
+    }
+
+    if (!hueFileEntry.document()) {
+      hueFileEntry.loadDocument();
+    }
+
+    $shareDocMocal = $(
+      '<div id="shareDocModal" data-bind="component: { name: \'share-doc-modal\', params: $data }" data-keyboard="true" class="modal hide fade" tabindex="-1"/>'
+    );
+    $('body').append($shareDocMocal);
+
+    ko.applyBindings(hueFileEntry, $shareDocMocal[0]);
+    $shareDocMocal.modal('show');
+  });
+});

+ 1 - 0
desktop/core/src/desktop/js/ko/ko.all.js

@@ -163,6 +163,7 @@ import 'ko/components/ko.pollingCatalogEntriesList';
 import 'ko/components/ko.sentryPrivileges';
 import 'ko/components/ko.sessionAuthModal';
 import 'ko/components/ko.sessionPanel';
+import 'ko/components/ko.shareDocModal';
 import 'ko/components/ko.sidebar';
 import 'ko/components/ko.sqlColumnsTable';
 

+ 1 - 74
desktop/core/src/desktop/templates/document_browser.mako

@@ -32,79 +32,6 @@ from desktop.views import _ko
       <i class="fa fa-fw"></i><span class="drag-text">4 entries</span>
     </div>
 
-    <div id="shareDocumentModal"  class="modal hide fade">
-      <!-- ko with: activeEntry -->
-      <!-- ko with: selectedEntry -->
-      <!-- ko with: document -->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
-        <h2 class="modal-title">${_('Sharing')} - <span data-bind="text: $parent.definition().name"></span></h2>
-      </div>
-      <div class="modal-body" style="overflow: visible; height: 240px">
-        <!-- ko with: definition -->
-        <div class="row-fluid" data-bind="visible: !$parent.hasErrors()" style="max-height: 114px;" id="scrolldiv">
-          <div class="span6">
-            <h4 class="muted" style="margin-top:0px">${_('Read')}</h4>
-            <div data-bind="visible: (perms.read.users.length == 0 && perms.read.groups.length == 0)">${_('The document is not shared for read.')}</div>
-            <ul class="unstyled airy" data-bind="foreach: perms.read.users">
-              <li>
-                <span class="badge badge-info" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-user"></i> <span data-bind="text: $parents[1].prettifyUsernameById(id), attr:{'data-id': id}"></span></span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeUserReadShare($data) }"> <i class="fa fa-times"></i></span>
-              </li>
-            </ul>
-            <ul class="unstyled airy" data-bind="foreach: perms.read.groups">
-              <li>
-                <span class="badge badge-info" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-users"></i> ${ _('Group') } &quot;<span data-bind="text: name"></span>&quot;</span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeGroupReadShare($data) }"> <i class="fa fa-times"></i></span>
-              </li>
-            </ul>
-          </div>
-
-          <div class="span6">
-            <h4 class="muted" style="margin-top: 0">${_('Modify')}</h4>
-            <div data-bind="visible: (perms.write.users.length == 0 && perms.write.groups.length == 0)">${_('The document is not shared for modify.')}</div>
-            <ul class="unstyled airy" data-bind="foreach: perms.write.users">
-              <li>
-                <span class="badge badge-info badge-left" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-user"></i> <span data-bind="text: $parents[1].prettifyUsernameById(id), attr:{'data-id': id}"></span></span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeUserWriteShare($data) }"> <i class="fa fa-times"></i></span>
-              </li>
-            </ul>
-            <ul class="unstyled airy" data-bind="foreach: perms.write.groups">
-              <li>
-                <span class="badge badge-info badge-left" data-bind="css: { 'badge-left' : $parents[1].fileEntry.canModify() }"><i class="fa fa-users"></i> ${ _('Group') } &quot;<span data-bind="text: name"></span>&quot;</span><span class="badge badge-right trash-share" data-bind="visible: $parents[1].fileEntry.canModify(), click: function() { $parents[1].removeGroupWriteShare($data) }"> <i class="fa fa-times"></i></span>
-              </li>
-            </ul>
-          </div>
-        </div>
-        <!-- /ko -->
-        <div class="doc-browser-empty animated" style="display: none;" data-bind="visible: loading">
-          <i class="fa fa-spinner fa-spin fa-2x" style="color: #999;"></i>
-        </div>
-        <div class="doc-browser-empty animated" style="display: none;" data-bind="visible: hasErrors() && ! loading()">
-          ${ _('There was an error loading the document.')}
-        </div>
-        <div style="margin-top: 20px" data-bind="visible: fileEntry.canModify() && ! hasErrors() && ! loading()">
-          <div class="input-append" style="font-size: inherit">
-            <div id="menu"></div>
-            <input id="userSearchAutocomp" placeholder="${_('Type a username or a group name')}" type="text" data-bind="autocomplete: { source: shareAutocompleteUserSource.bind($data), itemTemplate: 'user-search-autocomp-item', noMatchTemplate: 'user-search-autocomp-no-match', valueObservable: searchInput, showSpinner: true, classPrefix: 'hue-', onEnter: onShareAutocompleteUserEnter.bind($data), appendTo: $('#menu') }, clearable: { value: searchInput, textInput: searchInput }" class="ui-autocomplete-input" autocomplete="off" style="width: 420px">
-            <div class="btn-group" style="overflow:visible">
-              <a id="documentShareAddBtn" class="btn" data-bind="click: function () {  onShareAutocompleteUserEnter() }"><span data-bind="text: selectedPerm() == 'read' ? '${ _('Read') }' : '${ _('Modify') }'"></span></a>
-              <a id="documentShareCaret" class="btn dropdown-toggle" data-toggle="dropdown">
-               <span class="caret"></span>
-              </a>
-              <ul class="dropdown-menu">
-                <li><a data-bind="click: function () { selectedPerm('read'); onShareAutocompleteUserEnter() }" href="javascript:void(0)"><i class="fa fa-plus"></i> ${ _('Read') }</a></li>
-                <li><a data-bind="click: function () { selectedPerm('write'); onShareAutocompleteUserEnter() }" href="javascript:void(0)"><i class="fa fa-plus"></i> ${ _('Modify') }</a></li>
-              </ul>
-            </div>
-          </div>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <a href="#" data-dismiss="modal" class="btn disable-feedback disable-enter">${_('Close')}</a>
-      </div>
-      <!-- /ko -->
-      <!-- /ko -->
-      <!-- /ko -->
-    </div>
-
     <div id="renameDirectoryModal" data-keyboard="true" class="modal hide fade" tabindex="-1">
       <!-- ko with: activeEntry -->
       <form class="form-horizontal">
@@ -232,7 +159,7 @@ from desktop.views import _ko
                 <!-- /ko -->
 
                 <!-- ko if: app === 'documents' -->
-                <a class="btn" title="${_('Share')}" href="javascript:void(0);" data-bind="tooltip: { placement: 'bottom', delay: 750 }, click: function() { showSharingModal(null) }, css: { 'disabled': selectedEntries().length !== 1 || (selectedEntries().length === 1 && selectedEntries()[0].isTrashed) }"><i class="fa fa-fw fa-users"></i></a>
+                <a class="btn" title="${_('Share')}" href="javascript:void(0);" data-bind="tooltip: { placement: 'bottom', delay: 750 }, click: function() { showSharingModal() }, css: { 'disabled': selectedEntries().length !== 1 || (selectedEntries().length === 1 && selectedEntries()[0].isTrashed) }"><i class="fa fa-fw fa-users"></i></a>
                 <!-- /ko -->
 
                 <!-- ko if: app === 'documents' -->

+ 28 - 0
desktop/core/src/desktop/templates/global_js_constants.mako

@@ -158,6 +158,7 @@
     'at cursor': '${ _('at cursor') }',
     'Australia': '${ _('Australia') }',
     'Back': '${_('Back')}',
+    'Bar Chart': '${ _('Bar Chart') }',
     'Bars': '${ _('Bars') }',
     'Brazil': '${ _('Brazil') }',
     'Browse column privileges': '${_('Browse column privileges')}',
@@ -170,6 +171,7 @@
     'Cancel upload': '${ _('Cancel upload') }',
     'Cancel': '${_('Cancel')}',
     'Change': '${ _('Change') }',
+    'Chart': '${ _('Chart') }',
     'Check compatibility': '${ _('Check compatibility') }',
     'China': '${ _('China') }',
     'Choose a column to pivot...': '${ _('Choose a column to pivot...') }',
@@ -187,6 +189,7 @@
     'Cluster': '${ _('Cluster') }',
     'Clusters': '${ _('Clusters') }',
     'CodeGen': '${ _('CodeGen') }',
+    'Collapse': '${ _('Collapse') }',
     'Collection': '${ _('Collection') }',
     'column name...': '${_('column name...')}',
     'Column': '${ _('Column') }',
@@ -232,7 +235,10 @@
     'distinct': '${ _('distinct') }',
     'Do you really want to delete the following document(s)?': '${ _('Do you really want to delete the following document(s)?') }',
     'Document type': '${ _('Document type') }',
+    'Documentation': '${ _('Documentation') }',
     'Documents': '${ _('Documents') }',
+    'Done. 0 results.': '${ _('Done. 0 results.') }',
+    'Done.': '${ _('Done.') }',
     'Drop a SQL file here': '${_('Drop a SQL file here')}',
     'Drop iPython/Zeppelin notebooks here': '${_('Drop iPython/Zeppelin notebooks here')}',
     'Edit Profile': '${ _('Edit Profile') }',
@@ -260,6 +266,7 @@
     'Execution': '${ _('Execution') }',
     'Expand to all columns': '${ _('Expand to all columns') }',
     'Expand to selected columns': '${ _('Expand to selected columns') }',
+    'Expand': '${ _('Expand') }',
     'Expected end of statement': '${_('Expected end of statement')}',
     'Explain the current SQL query': '${ _('Explain the current SQL query') }',
     'Explain': '${ _('Explain') }',
@@ -286,7 +293,10 @@
     'Get hints on how to port SQL from other databases': '${ _('Get hints on how to port SQL from other databases') }',
     'Go Home': '${_('Go Home')}',
     'Go to column:': '${_('Go to column:')}',
+    'Gradient Map': '${ _('Gradient Map') }',
+    'Grid': '${ _('Grid') }',
     'group by': '${ _('group by') }',
+    'Group': '${ _('Group') }',
     'group': '${ _('group') }',
     'HBase': '${ _('HBase') }',
     'Heatmap': '${ _('Heatmap') }',
@@ -336,11 +346,13 @@
     'Lines': '${ _('Lines') }',
     'Load recent queries in order to improve recommendations': '${ _('Load recent queries in order to improve recommendations') }',
     'Loading metrics...': '${ _('Loading metrics...') }',
+    'Loading...': '${ _('Loading...') }',
     'Lock this row': '${_('Lock this row')}',
     'longitude': '${ _('longitude') }',
     'Manage Users': '${ _('Manage Users') }',
     'Manual refresh': '${_('Manual refresh')}',
     'MapReduce Job': '${_('MapReduce Job')}',
+    'Marker Map': '${ _('Marker Map') }',
     'Markers': '${ _('Markers') }',
     'max': '${ _('max') }',
     'Memory': '${ _('Memory') }',
@@ -354,6 +366,7 @@
     'Missing value configuration.': '${ _('Missing value configuration.') }',
     'Missing x axis configuration.': '${ _('Missing x axis configuration.') }',
     'Missing y axis configuration.': '${ _('Missing y axis configuration.') }',
+    'Modify': '${ _('Modify') }',
     'More': '${ _('More') }',
     'My Profile': '${ _('My Profile') }',
     'Name': '${ _('Name') }',
@@ -419,6 +432,7 @@
     'Password': '${ _('Password') }',
     'Perform incremental metadata update.': '${ _('Perform incremental metadata update.') }',
     'Permissions': '${ _('Permissions') }',
+    'Pie Chart': '${ _('Pie Chart') }',
     'Pig Design': '${_('Pig Design')}',
     'Pig Script': '${_('Pig Script')}',
     'Pin': '${_('Pin')}',
@@ -439,12 +453,14 @@
     'queued': '${ _('queued') }',
     'Re-create session': '${ _('Re-create session') }',
     'Re-create': '${ _('Re-create') }',
+    'Read': '${ _('Read') }',
     'Refresh': '${ _('Refresh') }',
     'region': '${ _('region') }',
     'Remove': '${ _('Remove') }',
     'Replace the editor content...': '${ _('Replace the editor content...') }',
     'Result available': '${ _('Result available') }',
     'Result expired': '${ _('Result expired') }',
+    'Result image': '${ _('Result image') }',
     'result(s) copied to the clipboard' : '${ _('result(s) copied to the clipboard') }',
     'Results have expired, rerun the query if needed.': '${ _('Results have expired, rerun the query if needed.') }',
     'Risks': '${ _('Risks') }',
@@ -457,6 +473,7 @@
     'Save session settings as default': '${ _('Save session settings as default') }',
     'Save': '${ _('Save') }',
     'scatter group': '${ _('scatter group') }',
+    'Scatter Plot': '${ _('Scatter Plot') }',
     'scatter size': '${ _('scatter size') }',
     'Schedule': '${ _('Schedule') }',
     'scope': '${ _('scope') }',
@@ -465,6 +482,7 @@
     'Search saved documents...': '${_('Search saved documents...')}',
     'Search': '${ _('Search') }',
     'Select a query or start typing to get optimization hints.': '${_('Select a query or start typing to get optimization hints')}',
+    'Select and execute a query to see the result.': '${ _('Select and execute a query to see the result.') }',
     'Select json file': '${ _('Select json file') }',
     'Select the chart parameters on the left': '${ _('Select the chart parameters on the left') }',
     'Select this folder': '${_('Select this folder')}',
@@ -476,6 +494,8 @@
     'Set as default application': '${_('Set as default application')}',
     'Set as default settings': '${_('Set as default settings')}',
     'Settings': '${ _('Settings') }',
+    'Share': '${ _('Share') }',
+    'Sharing': '${ _('Sharing') }',
     'Shell Script': '${_('Shell Script')}',
     'Show 50 more...': '${_('Show 50 more...')}',
     'Show advanced': '${_('Show advanced')}',
@@ -500,9 +520,12 @@
     'Starting': '${_('Starting')}',
     'Statement': '${ _('Statement') }',
     'Stats': '${_('Stats')}',
+    'Stop batch': '${ _('Stop batch') }',
     'Stop': '${ _('Stop') }',
     'Stopped': '${_('Stopped')}',
+    'Stopping': '${ _('Stopping') }',
     'Streams': '${ _('Streams') }',
+    'Success.': '${ _('Success.') }',
     'Summary': '${_('Summary')}',
     'Table Browser': '${ _('Table Browser') }',
     'table': '${ _('table') }',
@@ -512,6 +535,8 @@
     'Tags could not be loaded.': '${ _('Tags could not be loaded.') }',
     'Task History': '${ _('Task History') }',
     'Terms': '${ _('Terms') }',
+    'The document is not shared for modify.': '${ _('The document is not shared for modify.') }',
+    'The document is not shared for read.': '${ _('The document is not shared for read.') }',
     'The file has not been found': '${_('The file has not been found')}',
     'The table has no columns': '${_('The table has no columns')}',
     'The trash is empty': '${_('The trash is empty')}',
@@ -524,12 +549,15 @@
     'There was a problem loading the index preview': '${ _('There was a problem loading the index preview') }',
     'There was a problem loading the indexes': '${ _('There was a problem loading the indexes') }',
     'There was a problem loading the table preview': '${ _('There was a problem loading the table preview') }',
+    'There was an error loading the document.': '${ _('There was an error loading the document.') }',
     'This field does not support stats': '${ _('This field does not support stats') }',
     'This will sync missing tables.': '${ _('This will sync missing tables.') }',
+    'Timeline Chart': '${ _('Timeline Chart') }',
     'Timeline': '${ _('Timeline') }',
     'Top down analysis': '${ _('Top down analysis') }',
     'Top Nodes': '${ _('Top Nodes') }',
     'Topics': '${ _('Topics') }',
+    'Type a username or a group name': '${ _('Type a username or a group name') }',
     'Type': '${ _('Type') }',
     'type': '${ _('type') }',
     'UDFs': '${ _('UDFs') }',