浏览代码

HUE-9013 [editor] Contain data table generation within the new result grid component

This also adds proper disposal to the result view
Johan Ahlen 6 年之前
父节点
当前提交
85ecb17da5

+ 17 - 0
desktop/core/src/desktop/js/apps/notebook/app.js

@@ -85,6 +85,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
         .addClass('hide');
     };
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     const createHueDatatable = (el, snippet, vm) => {
       let DATATABLES_MAX_HEIGHT = 330;
       let invisibleRows = 10;
@@ -159,6 +160,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       return _dt;
     };
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     const createDatatable = (el, snippet, vm) => {
       const parent = $(el).parent();
       // When executing few columns -> many columns -> few columns we have to clear the style
@@ -314,6 +316,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
 
     window.hideFixedHeaders = hideFixedHeaders;
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     let redrawTimeout = -1;
     const redrawFixedHeaders = function(timeout) {
       const renderer = function() {
@@ -600,6 +603,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       huePubSub.publish('editor.presentation.operate.toggle', newValue);
     });
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     viewModel.isLeftPanelVisible.subscribe(value => {
       redrawFixedHeaders(200);
     });
@@ -750,6 +754,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       );
     });
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     const resetResultsResizer = snippet => {
       const $snippet = $('#snippet_' + snippet.id());
       $snippet
@@ -811,6 +816,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       });
     };
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     const resizeToggleResultSettings = (snippet, initial) => {
       let _dtElement;
       const $snip = $('#snippet_' + snippet.id());
@@ -898,6 +904,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       HUE_PUB_SUB_EDITOR_ID
     );
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2?
     huePubSub.subscribe(
       'redraw.fixed.headers',
       () => {
@@ -1141,6 +1148,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
 
     huePubSub.subscribe('editor.save', saveKeyHandler, HUE_PUB_SUB_EDITOR_ID);
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     huePubSub.subscribe(
       'editor.render.data',
       options => {
@@ -1195,6 +1203,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       HUE_PUB_SUB_EDITOR_ID
     );
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     huePubSub.subscribe(
       'editor.snippet.result.gray',
       snippet => {
@@ -1207,6 +1216,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       HUE_PUB_SUB_EDITOR_ID
     );
 
+    // TODO: Remove with ENABLE_NOTEBOOK_2
     huePubSub.subscribe(
       'editor.snippet.result.normal',
       snippet => {
@@ -1389,6 +1399,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       $('#clearHistoryModal' + window.EDITOR_SUFFIX).modal('hide');
     });
 
+    // TODO: Migrate to ko.resultChart.js for ENABLE_NOTEBOOK_2
     $(document).on('toggleResultSettings', (e, snippet) => {
       window.setTimeout(() => {
         const $snip = $('#snippet_' + snippet.id());
@@ -1411,14 +1422,17 @@ huePubSub.subscribe('app.dom.loaded', app => {
       }, 10);
     });
 
+    // TODO: Migrate to ko.resultChart.js for ENABLE_NOTEBOOK_2
     $(document).on('editorSizeChanged', () => {
       window.setTimeout(forceChartDraws, 50);
     });
 
+    // TODO: Migrate to ko.resultChart.js for ENABLE_NOTEBOOK_2
     $(document).on('redrawResults', () => {
       window.setTimeout(forceChartDraws, 50);
     });
 
+    // TODO: Migrate to ko.resultGrid.js for ENABLE_NOTEBOOK_2
     $(document).on('executeStarted', (e, options) => {
       const $snip = $('#snippet_' + options.snippet.id());
       const $el = $snip.find('.resultTable');
@@ -1448,6 +1462,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       }
     });
 
+    // TODO: Migrate to ko.resultGrid.js for ENABLE_NOTEBOOK_2
     $(document).on('renderDataError', (e, options) => {
       huePubSub.publish('editor.snippet.result.normal', options.snippet);
     });
@@ -1471,6 +1486,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       }
     });
 
+    // TODO: Migrate to ko.resultChart.js for ENABLE_NOTEBOOK_2
     $(document).on('forceChartDraw', (e, snippet) => {
       window.setTimeout(() => {
         snippet.chartX.notifySubscribers();
@@ -1489,6 +1505,7 @@ huePubSub.subscribe('app.dom.loaded', app => {
       }, 100);
     });
 
+    // TODO: Migrate to ko.resultChart.js for ENABLE_NOTEBOOK_2
     let _resizeTimeout = -1;
     $(window).on('resize', () => {
       huePubSub.publish('recalculate.name.description.width');

+ 438 - 2
desktop/core/src/desktop/js/apps/notebook2/components/resultGrid/ko.resultGrid.js

@@ -14,9 +14,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import $ from 'jquery';
+
 import componentUtils from 'ko/components/componentUtils';
 import DisposableComponent from 'ko/components/DisposableComponent';
 import I18n from 'utils/i18n';
+import huePubSub from 'utils/huePubSub';
+import { bootstrapRatios, defer, sleep } from 'utils/hueUtils';
 
 export const NAME = 'result-grid';
 
@@ -116,14 +120,23 @@ const TEMPLATE = `
         ">
         <pre class="margin-top-10"><i class="fa fa-check muted"></i> ${ I18n("Results have expired, rerun the query if needed.") }</pre>
       </div>
+      <span data-bind="template: { afterRender: resultTableRendered.bind($data) }"></span>
     </div>
   </div>
 </div>
 `;
 
 class ResultGrid extends DisposableComponent {
-  constructor(params) {
+  constructor(params, element) {
     super();
+    this.element = element;
+
+    this.isResultFullScreenMode = params.isResultFullScreenMode;
+    this.editorMode = params.editorMode;
+    this.isPresentationMode = params.isPresentationMode;
+    this.hasMore = params.hasMore;
+    this.fetchResult = params.fetchResult;
+
     this.status = params.status;
     this.isResultSettingsVisible = params.isResultSettingsVisible;
     this.isMetaFilterVisible = params.isMetaFilterVisible; // result
@@ -138,7 +151,430 @@ class ResultGrid extends DisposableComponent {
     this.resultsKlass = params.resultsKlass;
     this.meta = params.meta; // result
     this.data = params.data; // result
+
+    this.hueDatatable;
+
+    const dataSub = this.data.subscribe(() => {
+      this.render();
+    });
+
+    this.disposals.push(() => {
+      dataSub.dispose();
+      if (this.hueDatatable) {
+        this.hueDatatable.fnDestroy();
+      }
+    });
+  }
+
+  createHueDatatable() {
+    const $resultTable = this.getResultTableElement();
+    let datatablesMaxHeight = 330;
+    let invisibleRows = 10;
+    if (this.data().length) {
+      const colCount = this.data()[0].length;
+      invisibleRows = colCount > 200 ? 10 : colCount > 30 ? 50 : 100;
+    }
+    const $datatablesWrapper = $resultTable.parents('.dataTables_wrapper');
+
+    const hueDatatable = $resultTable.hueDataTable({
+      i18n: {
+        NO_RESULTS: I18n('No results found.'),
+        OF: I18n('of')
+      },
+      fnDrawCallback: () => {
+        const $resultTable = this.getResultTableElement();
+        if (this.editorMode()) {
+          $('#queryResults').removeAttr('style');
+          datatablesMaxHeight = $(window).height() - $resultTable.parent().offset().top - 40;
+          $datatablesWrapper.css('overflow-x', 'hidden');
+          $resultTable.jHueHorizontalScrollbar();
+          $datatablesWrapper.jHueScrollLeft();
+        } else if ($resultTable.data('fnDraws') === 1) {
+          $datatablesWrapper.jHueTableScroller({
+            maxHeight: datatablesMaxHeight,
+            heightAfterCorrection: 0
+          });
+          this.disposals.push(() => {
+            $datatablesWrapper.data('plugin_jHueTableScroller').destroy();
+          });
+        }
+      },
+      scrollable:
+        this.editorMode() && !this.isPresentationMode()
+          ? window.MAIN_SCROLLABLE
+          : '.dataTables_wrapper',
+      contained: !this.editorMode() || this.isPresentationMode(),
+      forceInvisible: invisibleRows
+    });
+
+    this.disposals.push(() => {
+      hueDatatable.fnDestroy();
+    });
+
+    defer(() => {
+      const $resultTable = this.getResultTableElement();
+
+      const tableExtenderOptions = {
+        mainScrollable: window.MAIN_SCROLLABLE,
+        fixedFirstColumn: this.editorMode(),
+        parentId: $resultTable.parents('.snippet').attr('id'),
+        clonedContainerPosition: 'fixed',
+        app: 'editor'
+      };
+      if (this.editorMode()) {
+        $resultTable.parents('.dataTables_wrapper').css('overflow-x', 'hidden');
+        const bannerTopHeight = window.BANNER_TOP_HTML ? 30 : 2;
+        tableExtenderOptions.stickToTopPosition = 48 + bannerTopHeight;
+      } else {
+        tableExtenderOptions.mainScrollable = $datatablesWrapper[0];
+        tableExtenderOptions.clonedContainerPosition = 'absolute';
+      }
+
+      $resultTable.jHueTableExtender2(tableExtenderOptions);
+
+      this.disposals.push(() => {
+        $resultTable.data('plugin_jHueTableExtender2').destroy();
+      });
+
+      if (this.editorMode()) {
+        $resultTable.jHueHorizontalScrollbar();
+      }
+    });
+
+    return hueDatatable;
+  }
+
+  createDatatable() {
+    const $resultTable = this.getResultTableElement();
+    const $resultTableParent = $resultTable.parent();
+    // When executing few columns -> many columns -> few columns we have to clear the style
+    $resultTable.removeAttr('style');
+    if ($resultTable.hasClass('table-huedatatable')) {
+      $resultTable.removeClass('table-huedatatable');
+      if ($resultTableParent.hasClass('dataTables_wrapper')) {
+        $resultTable.unwrap();
+      }
+    }
+    $resultTable.addClass('dt');
+
+    const hueDatatable = this.createHueDatatable($resultTable);
+
+    const $dataTablesWrapper = $resultTable.parents('.dataTables_wrapper');
+
+    if (!this.editorMode()) {
+      $dataTablesWrapper.on(
+        'mousewheel.resultGrid DOMMouseScroll.resultGrid wheel.resultGrid',
+        function(event) {
+          if ($resultTable.closest('.results').css('overflow') === 'hidden') {
+            return;
+          }
+          const originalEvent = event.originalEvent,
+            _deltaX = originalEvent.wheelDeltaX || -originalEvent.deltaX,
+            _deltaY = originalEvent.wheelDeltaY || -originalEvent.deltaY;
+          this.scrollTop += -_deltaY / 2;
+          this.scrollLeft += -_deltaX / 2;
+
+          if (this.scrollTop === 0) {
+            $('body')[0].scrollTop += -_deltaY / 3;
+            $('html')[0].scrollTop += -_deltaY / 3; // for firefox
+          }
+          event.preventDefault();
+        }
+      );
+
+      this.disposals.push(() => {
+        $dataTablesWrapper.off('mousewheel.resultGrid DOMMouseScroll.resultGrid wheel.resultGrid');
+      });
+    }
+
+    let $scrollElement = $dataTablesWrapper;
+    if (this.editorMode()) {
+      $scrollElement = $(window.MAIN_SCROLLABLE);
+    }
+
+    $scrollElement.off('scroll.resultGrid');
+    let scrollThrottle = -1;
+    let resultFollowTimeout = -1;
+
+    this.disposals.push(() => {
+      window.clearTimeout(scrollThrottle);
+      window.clearTimeout(resultFollowTimeout);
+    });
+
+    const dataScroll = () => {
+      const $resultTable = this.getResultTableElement();
+      if ($resultTable.is(':visible')) {
+        return;
+      }
+      const $snippet = this.getSnippetElement();
+      if (this.editorMode()) {
+        window.clearTimeout(resultFollowTimeout);
+        resultFollowTimeout = window.setTimeout(() => {
+          const topCoord = this.isPresentationMode() || this.isResultFullScreenMode() ? 50 : 73;
+          let offsetTop = 0;
+          if ($dataTablesWrapper.length > 0 && $dataTablesWrapper.offset()) {
+            offsetTop = ($dataTablesWrapper.offset().top - topCoord) * -1;
+          }
+          let margin = Math.max(offsetTop, 0);
+          if (window.BANNER_TOP_HTML) {
+            margin += 31;
+          }
+          if (this.isResultSettingsVisible()) {
+            $snippet.find('.snippet-grid-settings').css({
+              height:
+                this.isPresentationMode() || !this.editorMode()
+                  ? '330px'
+                  : Math.max(
+                      100,
+                      Math.ceil(
+                        $(window).height() - Math.max($('#queryResults').offset().top, topCoord)
+                      )
+                    ) + 'px'
+            });
+            $snippet.find('.result-settings').css({
+              marginTop: margin
+            });
+          }
+          $snippet.find('.snippet-actions').css({
+            marginTop: margin + 25
+          });
+        }, 100);
+      } else {
+        let lastScrollPosition =
+          $scrollElement.data('scrollPosition') != null ? $scrollElement.data('scrollPosition') : 0;
+        window.clearTimeout(scrollThrottle);
+        $scrollElement.data('scrollPosition', $scrollElement.scrollTop());
+        scrollThrottle = window.setTimeout(() => {
+          if (this.editorMode()) {
+            lastScrollPosition--; //hack for forcing fetching
+          }
+          if (
+            lastScrollPosition !== $scrollElement.scrollTop() &&
+            $scrollElement.scrollTop() + $scrollElement.outerHeight() + 20 >=
+              $scrollElement[0].scrollHeight &&
+            hueDatatable &&
+            this.hasMore()
+          ) {
+            this.showGrayedOutResult();
+            this.fetchResult(100, false);
+          }
+        }, 100);
+      }
+    };
+    $scrollElement.on('scroll.resultGrid', dataScroll);
+    this.disposals.push(() => {
+      $scrollElement.off('scroll.resultGrid');
+    });
+    this.isResultSettingsVisible.subscribe(newValue => {
+      if (newValue) {
+        dataScroll();
+      }
+    });
+
+    // huePubSub.subscribeOnce('chart.hard.reset', () => {
+    //   // hard reset once the default opened chart
+    //   const oldChartX = snippet.chartX();
+    //   snippet.chartX(null);
+    //   window.setTimeout(() => {
+    //     snippet.chartX(oldChartX);
+    //   }, 0);
+    // });
+
+    return hueDatatable;
+  }
+
+  getSnippetElement() {
+    return $(this.element).parents('.snippet');
+  }
+
+  getResultTableElement() {
+    return this.getSnippetElement().find('.resultTable');
+  }
+
+  resetResultsResizer() {
+    const $snippet = this.getSnippetElement();
+    $snippet
+      .find('.table-results .column-side')
+      .width(bootstrapRatios.span3() + '%')
+      .data('newWidth', bootstrapRatios.span3());
+    if (this.isResultSettingsVisible()) {
+      $snippet
+        .find('.table-results .grid-side')
+        .data('newWidth', bootstrapRatios.span9())
+        .width(bootstrapRatios.span9() + '%');
+    } else {
+      $snippet
+        .find('.table-results .grid-side')
+        .data('newWidth', 100)
+        .width('100%');
+    }
+    $snippet.find('.resize-bar').css('left', '');
+    try {
+      $snippet.find('.resize-bar').draggable('destroy');
+    } catch (e) {}
+
+    let initialPosition = 0;
+
+    $snippet.find('.resize-bar').draggable({
+      axis: 'x',
+      containment: $snippet.find('.table-results'),
+      create: () => {
+        const $snippet = this.getSnippetElement();
+        initialPosition = $snippet.find('.resize-bar').position().left;
+        $snippet.find('.table-results .column-side').data('newWidth', bootstrapRatios.span3());
+        $snippet
+          .find('.meta-filter')
+          .width($snippet.find('.table-results .column-side').width() - 28);
+      },
+      drag: (event, ui) => {
+        const $snippet = this.getSnippetElement();
+        if (initialPosition === 0) {
+          initialPosition = $snippet.find('.resize-bar').position().left;
+        }
+        ui.position.left = Math.max(150, ui.position.left);
+        const newSpan3Width = (ui.position.left * bootstrapRatios.span3()) / initialPosition;
+        const newSpan9Width = 100 - newSpan3Width - bootstrapRatios.margin();
+        $snippet
+          .find('.table-results .column-side')
+          .width(newSpan3Width + '%')
+          .data('newWidth', newSpan3Width);
+        $snippet
+          .find('.table-results .grid-side')
+          .width(newSpan9Width + '%')
+          .data('newWidth', newSpan9Width);
+        $snippet
+          .find('.meta-filter')
+          .width($snippet.find('.table-results .column-side').width() - 28);
+      },
+      stop: () => {
+        this.redrawFixedHeaders();
+        huePubSub.publish('resize.leaflet.map');
+      }
+    });
+  }
+
+  redrawFixedHeaders() {
+    const $snippet = this.getSnippetElement();
+    if (this.meta().length > 0) {
+      const tableExtender = $snippet.find('.resultTable').data('plugin_jHueTableExtender2');
+      if (tableExtender) {
+        tableExtender.repositionHeader();
+        tableExtender.drawLockedRows();
+      }
+      $(window.MAIN_SCROLLABLE).data('lastScroll', $(window.MAIN_SCROLLABLE).scrollTop());
+      $(window.MAIN_SCROLLABLE).trigger('scroll');
+    }
+    $snippet.find('.jHueTableExtenderClonedContainer').show();
+    $snippet.find('.jHueTableExtenderClonedContainerColumn').show();
+    $snippet.find('.jHueTableExtenderClonedContainerCell').show();
+    $snippet.find('.fixed-header-row').show();
+    $snippet.find('.fixed-first-cell').show();
+    $snippet.find('.fixed-first-column').show();
+  }
+
+  resizeToggleResultSettings(initial) {
+    let $datatablesWrapper;
+    const $snippet = this.getSnippetElement();
+    if ($snippet.find('.resultTable').is(':visible')) {
+      $datatablesWrapper = $snippet.find('.dataTables_wrapper');
+      const topCoord =
+        this.isPresentationMode() || this.isResultFullScreenMode()
+          ? window.BANNER_TOP_HTML
+            ? 31
+            : 1
+          : 73;
+      const $resultSettings = $('.result-settings');
+      $snippet.find('.snippet-grid-settings').css({
+        height:
+          this.isPresentationMode() || !this.editorMode()
+            ? '330px'
+            : Math.ceil(
+                $(window).height() -
+                  Math.max($resultSettings.length ? $resultSettings.offset().top : 0, topCoord)
+              ) + 'px'
+      });
+    } else {
+      $datatablesWrapper = $snippet.find('.chart:visible');
+    }
+    if ($datatablesWrapper.length === 0) {
+      $datatablesWrapper = $snippet.find('.table-results');
+    }
+    $datatablesWrapper
+      .parents('.snippet-body')
+      .find('.toggle-result-settings')
+      .css({
+        height: $datatablesWrapper.height() - 30 + 'px',
+        'line-height': $datatablesWrapper.height() - 30 + 'px'
+      });
+    if (initial) {
+      $snippet.find('.result-settings').css({
+        marginTop: 0
+      });
+      $snippet.find('.snippet-actions').css({
+        marginTop: 0
+      });
+      huePubSub.publish('resize.leaflet.map');
+    }
+  }
+
+  async render() {
+    const $snippet = this.getSnippetElement();
+    if (this.data().length > 0) {
+      await sleep(300);
+      const $resultTable = $snippet.find('.resultTable');
+      const initial = !$resultTable.data('rendered');
+      let dataTable;
+      if (!$resultTable.data('rendered')) {
+        this.meta.notifySubscribers();
+        $snippet.find('select').trigger('chosen:updated');
+        dataTable = this.createDatatable();
+        this.resetResultsResizer();
+        $resultTable.data('rendered', true);
+      } else {
+        dataTable = $resultTable.hueDataTable();
+      }
+      try {
+        dataTable.fnAddData(this.data());
+      } catch (e) {}
+      const $dataTablesWrapper = $snippet.find('.dataTables_wrapper');
+      this.showNormalResult();
+      $dataTablesWrapper.scrollTop($dataTablesWrapper.data('scrollPosition'));
+      this.redrawFixedHeaders();
+      this.resizeToggleResultSettings(initial);
+    } else {
+      this.showNormalResult();
+    }
+    $snippet.find('select').trigger('chosen:updated');
+    $snippet.find('.snippet-grid-settings').scrollLeft(0);
+  }
+
+  showGrayedOutResult() {
+    const $wrapper = this.getSnippetElement().find('.dataTables_wrapper');
+    $wrapper.find('.fixed-first-column').css({ opacity: '0' });
+    $wrapper.find('.fixed-header-row').css({ opacity: '0' });
+    $wrapper.find('.fixed-first-cell').css({ opacity: '0' });
+    $wrapper.find('.resultTable').css({ opacity: '0.55' });
+  }
+
+  showNormalResult() {
+    const $wrapper = this.getSnippetElement().find('.dataTables_wrapper');
+    $wrapper.find('.fixed-first-column').css({ opacity: '1' });
+    $wrapper.find('.fixed-header-row').css({ opacity: '1' });
+    $wrapper.find('.fixed-first-cell').css({ opacity: '1' });
+    $wrapper.find('.resultTable').css({ opacity: '1' });
+  }
+
+  async resultTableRendered() {
+    await defer(() => {
+      this.render(true);
+    });
   }
 }
 
-componentUtils.registerComponent(NAME, ResultGrid, TEMPLATE);
+componentUtils.registerComponent(
+  NAME,
+  {
+    createViewModel: (params, componentInfo) => new ResultGrid(params, componentInfo.element)
+  },
+  TEMPLATE
+);

+ 0 - 7
desktop/core/src/desktop/js/apps/notebook2/result.js

@@ -17,7 +17,6 @@
 import ko from 'knockout';
 
 import { sleep, UUID } from 'utils/hueUtils';
-import huePubSub from 'utils/huePubSub';
 
 const isNumericColumn = type =>
   ['tinyint', 'smallint', 'int', 'bigint', 'float', 'double', 'decimal', 'real'].indexOf(type) !==
@@ -276,12 +275,6 @@ class Result {
 
     this.images(resultResponse.images || []);
 
-    huePubSub.publish('editor.render.data', {
-      data: tempData,
-      snippet: this.snippet,
-      initial: initialIndex === 0
-    });
-
     if (!this.fetchedOnce()) {
       resultResponse.meta.unshift({ type: 'INT_TYPE', name: '', comment: null });
       this.meta(resultResponse.meta);

+ 4 - 1
desktop/core/src/desktop/js/spec/globalJsConstants.js

@@ -23,7 +23,10 @@ const globalVars = {
   HAS_OPTIMIZER: false,
   AUTOCOMPLETE_TIMEOUT: 1,
   HUE_I18n: {},
-  HUE_BASE_URL: ''
+  HUE_BASE_URL: '',
+  HUE_CHARTS: {
+    TYPES: 'bar'
+  }
 };
 
 Object.keys(globalVars).forEach(key => {

+ 5 - 0
desktop/core/src/desktop/js/utils/hueUtils.js

@@ -582,6 +582,11 @@ export const stripHtmlFromFunctions = template => {
 
 export const sleep = async timeout => new Promise(resolve => setTimeout(resolve, timeout));
 
+export const defer = async callback => {
+  await sleep(0);
+  callback();
+};
+
 export default {
   bootstrapRatios: bootstrapRatios,
   getFileBrowseButton: getFileBrowseButton,

+ 5 - 1
desktop/core/src/desktop/static/desktop/js/jquery.tablescroller.js

@@ -55,7 +55,7 @@
     if (disableScrollingTable == null || disableScrollingTable != true) {
       resizeScrollingTable(_this);
       var _resizeTimeout = -1;
-      $(window).resize(function () {
+      $(window).on('resize.jHueTableScroller', function () {
         window.clearTimeout(_resizeTimeout);
         _resizeTimeout = window.setTimeout(function(){
           resizeScrollingTable(_this);
@@ -64,6 +64,10 @@
     }
   };
 
+  Plugin.prototype.destroy = function () {
+    $(window).off('resize.jHueTableScroller');
+  };
+
   function resizeScrollingTable(_this) {
     var el = _this.element;
     $(el).css("overflow-y", "").css("height", "");

+ 5 - 0
desktop/libs/notebook/src/notebook/templates/editor_components2.mako

@@ -1335,6 +1335,11 @@
           <!-- ko if: showGrid -->
             <!-- ko component: { name: 'result-grid', params: {
               status: status,
+              isResultFullScreenMode: parentVm.isResultFullScreenMode,
+              editorMode: parentVm.editorMode,
+              isPresentationMode: parentNotebook.isPresentationMode,
+              hasMore: result.hasMore,
+              fetchResult: result.fetchMoreRows,
               isResultSettingsVisible: isResultSettingsVisible,
               isMetaFilterVisible: result.isMetaFilterVisible,
               filteredMeta: result.filteredMeta,