浏览代码

[notebook] Implement the clear history backend

Romain Rigaux 10 年之前
父节点
当前提交
f37d17d219

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

@@ -313,7 +313,7 @@ ${ assist.assistPanel() }
                 </div>
 
                 <div class="tile">
-                  <h4>${ _('Starred columns') } (<span data-bind="text: favouriteColumns().length"></span>)</h4>
+                  <h4>${ _('Columns') } (<span data-bind="text: favouriteColumns().length"></span>)</h4>
                   <!-- ko with: favouriteColumns -->
                   <!-- ko template: "metastore-columns-table" --><!-- /ko -->
                   <!-- /ko -->

+ 4 - 1
desktop/core/src/desktop/models.py

@@ -732,6 +732,9 @@ class Document2Manager(models.Manager):
   def get_by_natural_key(self, uuid, version, is_history):
     return self.get(uuid=uuid, version=version, is_history=is_history)
 
+  def get_history(self, user, doc_type):
+    return self.filter(owner=user, type=doc_type, is_history=True).order_by('-last_modified') # To do perm sharing
+
 
 def uuid_default():
   return str(uuid.uuid4())
@@ -801,7 +804,7 @@ class Document2(models.Model):
       return reverse('oozie:edit_coordinator') + '?coordinator=' + str(self.id)
     elif self.type == 'oozie-bundle2':
       return reverse('oozie:edit_bundle') + '?bundle=' + str(self.id)
-    elif self.type == 'query':
+    elif self.type.startswith('query'):
       return reverse('notebook:editor') + '?editor=' + str(self.id)
     elif self.type == 'notebook':
       return reverse('notebook:notebook') + '?notebook=' + str(self.id)

+ 30 - 9
desktop/libs/notebook/src/notebook/api.py

@@ -225,15 +225,15 @@ def save_notebook(request):
 
 
 @require_POST
-# @check_document_modify_permission()
+@check_document_modify_permission()
 def historify(request):
   response = {'status': -1}
 
-  parent = request.POST.get('parent_id')  # If we had an history to a saved notebook
   history = json.loads(request.POST.get('notebook', '{}'))
+  query_type = history['type']
 
-  history_doc = Document2.objects.create(name=history['name'], type='notebook', owner=request.user)
-  Document.objects.link(history_doc, owner=history_doc.owner, name=history_doc.name, description=history_doc.description, extra='notebook')
+  history_doc = Document2.objects.create(name=history['name'], type=query_type, owner=request.user, is_history=True)
+  Document.objects.link(history_doc, owner=history_doc.owner, name=history_doc.name, description=history_doc.description, extra=query_type)
 
   history_doc1 = history_doc.doc.get()
   history_doc.update_data(history)
@@ -243,27 +243,48 @@ def historify(request):
   history_doc.save()
   history_doc1.save()
 
-  if parent:
-    Document2.objects.get(id=parent['id']).dependencies.add(history_doc)
+  if history.get('id'): # If we come from a saved query
+    Document2.objects.get(id=history['id']).dependencies.add(history_doc)
 
   response['status'] = 0
   response['id'] = history_doc.id
-  response['message'] = _('Notebook saved !')
+  response['message'] = _('Query notebook history saved !')
 
   return JsonResponse(response)
 
 
+@require_GET
 def get_history(request):
   response = {'status': -1}
 
+  doc_type = request.GET.get('doc_type')
+
   response['status'] = 0
   response['history'] = [{
       'name': doc.name,
       'id': doc.id,
       'data': Notebook(document=doc).get_data(),
       'absoluteUrl': doc.get_absolute_url()
-      } for doc in Document2.objects.filter(type='notebook', owner=request.user, is_history=True).order_by('-last_modified')[:25]]
-  response['message'] = _('History saved !')
+      } for doc in Document2.objects.get_history(doc_type='query-%s' % doc_type, user=request.user)[:25]]
+  response['message'] = _('History fetched')
+
+  return JsonResponse(response)
+
+
+@require_POST
+@check_document_modify_permission()
+def clear_history(request):
+  response = {'status': -1}
+
+  notebook = json.loads(request.POST.get('notebook'), '{}')
+  doc_type = request.POST.get('doc_type')
+
+  response['status'] = 0
+  history = Document2.objects.get_history(doc_type='query-%s' % doc_type, user=request.user)
+  if notebook.get('id'):
+    history = history.exclude(id=notebook.get('id'))
+  response['updated'] = history.delete()
+  response['message'] = _('History cleared !')
 
   return JsonResponse(response)
 

+ 25 - 15
desktop/libs/notebook/src/notebook/static/notebook/js/notebook.ko.js

@@ -434,13 +434,15 @@
         self.close();
       }
 
-      $.post("/notebook/api/historify", {
-        notebook: ko.mapping.toJSON(self, SPARK_MAPPING)
-      }, function(data){
-        if (vm.editorMode && data && data.status == 0 && data.id && typeof history.pushState != 'undefined'){
-          history.pushState(null, null, '/notebook/editor?editor=' + data.id);
-        }
-      });
+      if (notebook.type() != 'notebook') {
+        $.post("/notebook/api/historify", {
+          notebook: ko.mapping.toJSON(self, SPARK_MAPPING)
+        }, function(data){
+          if (vm.editorMode && data && data.status == 0 && data.id && typeof history.pushState != 'undefined'){
+            history.pushState(null, null, '/notebook/editor?editor=' + data.id);
+          }
+        });
+      }
 
       $.post("/notebook/api/execute", {
         notebook: ko.mapping.toJSON(notebook.getContext()),
@@ -697,7 +699,7 @@
     self.uuid = ko.observable(typeof notebook.uuid != "undefined" && notebook.uuid != null ? notebook.uuid : UUID());
     self.name = ko.observable(typeof notebook.name != "undefined" && notebook.name != null ? notebook.name : 'My Notebook');
     self.description = ko.observable(typeof notebook.description != "undefined" && notebook.description != null ? notebook.description: '');
-    self.type = ko.observable(typeof notebook.type != "undefined" && notebook.type != null ? notebook.type: 'notebook');
+    self.type = ko.observable(typeof notebook.type != "undefined" && notebook.type != null ? notebook.type : 'notebook');
     self.snippets = ko.observableArray();
     self.selectedSnippet = ko.observable(vm.availableSnippets().length > 0 ? vm.availableSnippets()[0].type() : 'NO_SNIPPETS');
     self.creatingSessionLocks = ko.observableArray();
@@ -945,7 +947,7 @@
     };
 
     self.closeAndRemoveSession = function (session) {
-      self.closeSession (session, false, function() {
+      self.closeSession(session, false, function() {
         self.sessions.remove(session);
       });
     };
@@ -970,13 +972,15 @@
     };
 
     self.fetchHistory = function () {
-      $.get("/notebook/api/get_history", {}, function(data) {
+      $.get("/notebook/api/get_history", {
+        doc_type: self.selectedSnippet()
+      }, function(data) {
         var parsedHistory = [];
         if (data && data.history){
           data.history.forEach(function(nbk){
             parsedHistory.push({
               url: nbk.absoluteUrl,
-              query: nbk.data.statement_raw,
+              query: nbk.data.snippets[0].statement_raw,
               lastExecuted: nbk.data.lastExecuted
             });
           });
@@ -985,9 +989,15 @@
       });
     };
 
-    self.clearHistory = function () {
-      // TODO
-      console.log("clear history")
+    self.clearHistory = function (type) {
+      $.post("/notebook/api/clear_history", {
+        notebook: ko.mapping.toJSON(self.getContext()),
+        doc_type: self.selectedSnippet()
+      }, function (data) {
+          self.history.removeAll();
+        }).fail(function (xhr) {
+           $(document).trigger("error", xhr.responseText);
+        });
       $(document).trigger("hideHistoryModal");
     };
 
@@ -1126,7 +1136,7 @@
 
     self.availableSnippets = ko.mapping.fromJS(options.languages);
 
-    self.editorMode = self.availableSnippets().length === 1;
+    self.editorMode = options.mode == 'editor';
 
     self.getSnippetViewSettings = function (snippetType) {
       if (options.snippetViewSettings[snippetType]) {

+ 1 - 0
desktop/libs/notebook/src/notebook/urls.py

@@ -57,6 +57,7 @@ urlpatterns += patterns('notebook.api',
 
   url(r'^api/historify$', 'historify', name='historify'),
   url(r'^api/get_history', 'get_history', name='get_history'),
+  url(r'^api/clear_history', 'clear_history', name='clear_history'),
 
   url(r'^api/notebook/save$', 'save_notebook', name='save_notebook'),
   url(r'^api/notebook/open$', 'open_notebook', name='open_notebook'),

+ 5 - 4
desktop/libs/notebook/src/notebook/views.py

@@ -62,7 +62,7 @@ def notebook(request):
       'notebooks_json': json.dumps([notebook.get_data()]),
       'options_json': json.dumps({
           'languages': get_interpreters(request.user),
-          'session_properties': SparkApi.PROPERTIES
+          'session_properties': SparkApi.PROPERTIES,
       }),
       'autocomplete_base_url': autocomplete_base_url,
       'is_yarn_mode': is_yarn_mode
@@ -80,7 +80,7 @@ def editor(request):
     editor = Notebook()
     data = editor.get_data()
     data['name'] = '%s Query' % editor_type.title()
-    data['type'] = 'query'
+    data['type'] = 'query-%s' % editor_type
     editor.data = json.dumps(data)
 
   autocomplete_base_url = ''
@@ -92,7 +92,8 @@ def editor(request):
   return render('editor.mako', request, {
       'notebooks_json': json.dumps([editor.get_data()]),
       'options_json': json.dumps({
-          'languages': [{"name": "%s SQL" % editor_type.title(), "type": editor_type}]
+          'languages': [{"name": "%s SQL" % editor_type.title(), "type": editor_type}],
+          'mode': 'editor',
       }),
       'editor_type': editor_type,
       'autocomplete_base_url': autocomplete_base_url,
@@ -104,7 +105,7 @@ def new(request):
 
 
 def notebooks(request):
-  notebooks = [d.content_object.to_dict() for d in Document.objects.get_docs(request.user, Document2, qfilter=Q(extra='notebook') | Q(extra='query')) if not d.content_object.is_history]
+  notebooks = [d.content_object.to_dict() for d in Document.objects.get_docs(request.user, Document2, qfilter=Q(extra='notebook') | Q(extra__startswith='query')) if not d.content_object.is_history]
 
   return render('notebooks.mako', request, {
       'notebooks_json': json.dumps(notebooks, cls=JSONEncoderForHTML)