Эх сурвалжийг харах

HUE-8893 [assist] Move remaining right assist panels into webpack and drop assist.mako

Johan Ahlen 6 жил өмнө
parent
commit
1adbf6d630
25 өөрчлөгдсөн 586 нэмэгдсэн , 518 устгасан
  1. 0 3
      apps/beeswax/src/beeswax/templates/create_database.mako
  2. 0 3
      apps/beeswax/src/beeswax/templates/create_table_manually.mako
  3. 0 3
      apps/beeswax/src/beeswax/templates/execute.mako
  4. 0 3
      apps/beeswax/src/beeswax/templates/import_wizard_choose_delimiter.mako
  5. 0 3
      apps/beeswax/src/beeswax/templates/import_wizard_choose_file.mako
  6. 0 3
      apps/beeswax/src/beeswax/templates/import_wizard_define_columns.mako
  7. 0 3
      apps/jobbrowser/src/jobbrowser/templates/job_browser.mako
  8. 0 3
      apps/metastore/src/metastore/templates/metastore.mako
  9. 189 0
      desktop/core/src/desktop/js/ko/components/assist/ko.assistDashboardPanel.js
  10. 2 0
      desktop/core/src/desktop/js/ko/components/assist/ko.assistEditorContextPanel.js
  11. 146 0
      desktop/core/src/desktop/js/ko/components/assist/ko.assistSchedulePanel.js
  12. 238 0
      desktop/core/src/desktop/js/ko/components/assist/ko.rightAssistPanel.js
  13. 3 0
      desktop/core/src/desktop/js/ko/ko.all.js
  14. 0 468
      desktop/core/src/desktop/templates/assist.mako
  15. 0 4
      desktop/core/src/desktop/templates/assist_m.mako
  16. 8 0
      desktop/core/src/desktop/templates/global_js_constants.mako
  17. 0 2
      desktop/core/src/desktop/templates/home2.mako
  18. 0 3
      desktop/core/src/desktop/templates/hue.mako
  19. 0 3
      desktop/libs/indexer/src/indexer/templates/importer.mako
  20. 0 3
      desktop/libs/indexer/src/indexer/templates/indexer.mako
  21. 0 3
      desktop/libs/indexer/src/indexer/templates/indexes.mako
  22. 0 3
      desktop/libs/indexer/src/indexer/templates/topics.mako
  23. 0 2
      desktop/libs/notebook/src/notebook/templates/editor.mako
  24. 0 1
      desktop/libs/notebook/src/notebook/templates/editor_m.mako
  25. 0 2
      desktop/libs/notebook/src/notebook/templates/notebook.mako

+ 0 - 3
apps/beeswax/src/beeswax/templates/create_database.mako

@@ -19,7 +19,6 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 
 
@@ -46,8 +45,6 @@ ${layout.metastore_menubar()}
 % endif
 % endif
 </style>
 </style>
 
 
-${ assist.assistPanel() }
-
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <i class="fa fa-chevron-right"></i>
   <i class="fa fa-chevron-right"></i>
 </a>
 </a>

+ 0 - 3
apps/beeswax/src/beeswax/templates/create_table_manually.mako

@@ -19,7 +19,6 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 
 
@@ -44,8 +43,6 @@ ${ layout.metastore_menubar() }
 % endif
 % endif
 </style>
 </style>
 
 
-${ assist.assistPanel() }
-
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <i class="fa fa-chevron-right"></i>
   <i class="fa fa-chevron-right"></i>
 </a>
 </a>

+ 0 - 3
apps/beeswax/src/beeswax/templates/execute.mako

@@ -23,7 +23,6 @@
   from notebook.conf import ENABLE_QUERY_BUILDER
   from notebook.conf import ENABLE_QUERY_BUILDER
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 
 
@@ -848,8 +847,6 @@ ${ commonshare() | n,unicode }
 
 
 <script src="${ static('beeswax/js/stats.utils.js') }"></script>
 <script src="${ static('beeswax/js/stats.utils.js') }"></script>
 
 
-${ assist.assistPanel() }
-
 <style type="text/css">
 <style type="text/css">
   h1 {
   h1 {
     margin-bottom: 5px;
     margin-bottom: 5px;

+ 0 - 3
apps/beeswax/src/beeswax/templates/import_wizard_choose_delimiter.mako

@@ -19,7 +19,6 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="util" file="util.mako" />
 <%namespace name="util" file="util.mako" />
@@ -44,8 +43,6 @@ ${ layout.metastore_menubar() }
 % endif
 % endif
 </style>
 </style>
 
 
-${ assist.assistPanel() }
-
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <i class="fa fa-chevron-right"></i>
   <i class="fa fa-chevron-right"></i>
 </a>
 </a>

+ 0 - 3
apps/beeswax/src/beeswax/templates/import_wizard_choose_file.mako

@@ -19,7 +19,6 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 
 
@@ -43,8 +42,6 @@ ${ layout.metastore_menubar() }
 % endif
 % endif
 </style>
 </style>
 
 
-${ assist.assistPanel() }
-
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <i class="fa fa-chevron-right"></i>
   <i class="fa fa-chevron-right"></i>
 </a>
 </a>

+ 0 - 3
apps/beeswax/src/beeswax/templates/import_wizard_define_columns.mako

@@ -19,7 +19,6 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="util" file="util.mako" />
 <%namespace name="util" file="util.mako" />
@@ -44,8 +43,6 @@ ${ layout.metastore_menubar() }
 % endif
 % endif
 </style>
 </style>
 
 
-${ assist.assistPanel() }
-
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
 <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <i class="fa fa-chevron-right"></i>
   <i class="fa fa-chevron-right"></i>
 </a>
 </a>

+ 0 - 3
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -29,7 +29,6 @@ SUFFIX = is_mini and "-mini" or ""
 
 
 % if not is_embeddable:
 % if not is_embeddable:
 ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
 ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
-<%namespace name="assist" file="/assist.mako" />
 % endif
 % endif
 
 
 <span class="notebook">
 <span class="notebook">
@@ -65,8 +64,6 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
 % endif
 % endif
 
 
 % if not is_embeddable:
 % if not is_embeddable:
-  ${ assist.assistPanel() }
-
   <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
   <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
     <i class="fa fa-chevron-right"></i>
     <i class="fa fa-chevron-right"></i>
   </a>
   </a>

+ 0 - 3
apps/metastore/src/metastore/templates/metastore.mako

@@ -27,7 +27,6 @@ from metastore.conf import ENABLE_NEW_CREATE_TABLE
 %>
 %>
 
 
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="components" file="components.mako" />
 <%namespace name="components" file="components.mako" />
 
 
 <%
 <%
@@ -54,8 +53,6 @@ ${ commonheader(_("Metastore"), app_name, user, request) | n,unicode }
   }
   }
 % endif
 % endif
 </style>
 </style>
-
-${ assist.assistPanel() }
 % endif
 % endif
 
 
 <script src="${ static('desktop/ext/js/wysihtml5-0.3.0.min.js') }"></script>
 <script src="${ static('desktop/ext/js/wysihtml5-0.3.0.min.js') }"></script>

+ 189 - 0
desktop/core/src/desktop/js/ko/components/assist/ko.assistDashboardPanel.js

@@ -0,0 +1,189 @@
+// 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 ko from 'knockout';
+
+import AssistDbEntry from 'ko/components/assist/assistDbEntry';
+import AssistDbSource from 'ko/components/assist/assistDbSource';
+import componentUtils from 'ko/components/componentUtils';
+import dataCatalog from 'catalog/dataCatalog';
+import huePubSub from 'utils/huePubSub';
+import { TEMPLATE, AssistantUtils } from 'ko/components/assist/ko.assistEditorContextPanel';
+
+class AssistDashboardPanel {
+  constructor() {
+    this.disposals = [];
+    this.isSolr = ko.observable(true);
+
+    this.showRisks = ko.observable(false);
+
+    this.filter = {
+      querySpec: ko
+        .observable({
+          query: '',
+          facets: {},
+          text: []
+        })
+        .extend({ rateLimit: 300 })
+    };
+
+    this.sourceType = ko.observable('solr');
+
+    this.activeTables = ko.observableArray();
+
+    this.filteredTables = AssistantUtils.getFilteredTablesPureComputed(this);
+
+    this.someLoading = ko.pureComputed(() => {
+      return this.activeTables().some(table => {
+        return table.loading() || (!table.hasEntries() && !table.hasErrors());
+      });
+    });
+
+    const navigationSettings = {
+      showStats: true,
+      rightAssist: true
+    };
+    const i18n = {};
+
+    const activeDashboardCollection = huePubSub.subscribe(
+      'set.active.dashboard.collection',
+      collection => {
+        const collectionName = collection.name();
+
+        if (!collectionName) {
+          return;
+        }
+
+        this.sourceType = ko.observable(collection.engine());
+
+        const assistDbSource = new AssistDbSource({
+          i18n: i18n,
+          initialNamespace: collection.activeNamespace,
+          initialCompute: collection.activeCompute,
+          type: collection.engine(),
+          name: collection.engine(),
+          nonSqlType: true,
+          navigationSettings: navigationSettings
+        });
+
+        const fakeParentName =
+          collectionName.indexOf('.') > -1 ? collectionName.split('.')[0] : 'default';
+
+        const sourceType =
+          collection.source() === 'query' ? collection.engine() + '-query' : collection.engine();
+
+        dataCatalog
+          .getEntry({
+            sourceType: sourceType,
+            namespace: collection.activeNamespace,
+            compute: collection.activeCompute,
+            path: [fakeParentName],
+            definition: { type: 'database' }
+          })
+          .done(fakeDbCatalogEntry => {
+            const assistFakeDb = new AssistDbEntry(
+              fakeDbCatalogEntry,
+              null,
+              assistDbSource,
+              this.filter,
+              i18n,
+              navigationSettings
+            );
+            dataCatalog
+              .getEntry({
+                sourceType: sourceType,
+                namespace: collection.activeNamespace,
+                compute: collection.activeCompute,
+                path: [
+                  fakeParentName,
+                  collectionName.indexOf('.') > -1 ? collectionName.split('.')[1] : collectionName
+                ],
+                definition: { type: 'table' }
+              })
+              .done(collectionCatalogEntry => {
+                const collectionEntry = new AssistDbEntry(
+                  collectionCatalogEntry,
+                  assistFakeDb,
+                  assistDbSource,
+                  this.filter,
+                  i18n,
+                  navigationSettings
+                );
+                this.activeTables([collectionEntry]);
+
+                if (
+                  !collectionEntry.loaded &&
+                  !collectionEntry.hasErrors() &&
+                  !collectionEntry.loading()
+                ) {
+                  collectionEntry.loadEntries(() => {
+                    collectionEntry.toggleOpen();
+                  });
+                }
+              });
+          });
+
+        this.autocompleteFromEntries = function(nonPartial, partial) {
+          const added = {};
+          const result = [];
+          const partialLower = partial.toLowerCase();
+          this.activeTables().forEach(table => {
+            if (
+              !added[table.catalogEntry.name] &&
+              table.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0
+            ) {
+              added[table.catalogEntry.name] = true;
+              result.push(nonPartial + partial + table.catalogEntry.name.substring(partial.length));
+            }
+            table.entries().forEach(col => {
+              if (
+                !added[col.catalogEntry.name] &&
+                col.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0
+              ) {
+                added[col.catalogEntry.name] = true;
+                result.push(nonPartial + partial + col.catalogEntry.name.substring(partial.length));
+              }
+            });
+          });
+          return result;
+        };
+      }
+    );
+
+    this.disposals.push(() => {
+      activeDashboardCollection.remove();
+    });
+  }
+
+  dispose() {
+    this.disposals.forEach(dispose => {
+      dispose();
+    });
+  }
+}
+
+let instance;
+
+const viewModelFactory = {
+  createViewModel: () => {
+    if (!instance) {
+      instance = new AssistDashboardPanel();
+    }
+    return instance;
+  }
+};
+
+componentUtils.registerComponent('assist-dashboard-panel', viewModelFactory, TEMPLATE);

+ 2 - 0
desktop/core/src/desktop/js/ko/components/assist/ko.assistEditorContextPanel.js

@@ -750,3 +750,5 @@ const viewModelFactory = {
 };
 };
 
 
 componentUtils.registerComponent('assist-editor-context-panel', viewModelFactory, TEMPLATE);
 componentUtils.registerComponent('assist-editor-context-panel', viewModelFactory, TEMPLATE);
+
+export { TEMPLATE, AssistantUtils };

+ 146 - 0
desktop/core/src/desktop/js/ko/components/assist/ko.assistSchedulePanel.js

@@ -0,0 +1,146 @@
+// 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 ko from 'knockout';
+
+import componentUtils from 'ko/components/componentUtils';
+import huePubSub from 'utils/huePubSub';
+import I18n from 'utils/i18n';
+
+const TEMPLATE = `
+  <div class="assist-inner-panel">
+    <div class="assist-flex-panel">
+      <!-- ko if: selectedNotebook() && selectedNotebook().isBatchable() -->
+      <!-- ko with: selectedNotebook() -->
+      <div class="tab-pane" id="scheduleTab">
+        <!-- ko ifnot: isSaved() && ! isHistory() -->
+        ${I18n('Query needs to be saved.')}
+        <!-- /ko -->
+        <!-- ko if: isSaved() && ! isHistory() -->
+          <!-- ko if: schedulerViewModelIsLoaded() && schedulerViewModel.coordinator.isDirty() -->
+          <a data-bind="click: saveScheduler" href="javascript: void(0);">${I18n(
+            'Save changes'
+          )}</a>
+          <!-- /ko -->
+          <!-- ko if: schedulerViewModelIsLoaded() && ! schedulerViewModel.coordinator.isDirty() && (! viewSchedulerId() || isSchedulerJobRunning() == false )-->
+          <a data-bind="click: showSubmitPopup" href="javascript: void(0);">${I18n('Start')}</a>
+          <!-- /ko -->
+          <!-- ko if: schedulerViewModelIsLoaded() && viewSchedulerId()-->
+          <a data-bind="click: function() { huePubSub.publish('show.jobs.panel', {id: viewSchedulerId(), interface: 'schedules'}) }, clickBubble: false" href="javascript: void(0);">
+            ${I18n('View')}
+          </a>
+          <!-- ko if: isSchedulerJobRunning() -->
+            ${I18n('Running')}
+          <!-- /ko -->
+          <!-- ko if: isSchedulerJobRunning() == false -->
+            ${I18n('Stopped')}
+          <!-- /ko -->
+        <!-- /ko -->
+        <!-- /ko -->
+        <br>
+        <br>
+        <div id="schedulerEditor"></div>
+      </div>
+      <!-- /ko -->
+      <!-- /ko -->
+    </div>
+  </div>
+`;
+
+class AssistSchedulePanel {
+  constructor() {
+    this.disposals = [];
+    this.selectedNotebook = ko.observable();
+
+    // TODO: Move all the scheduler logic out of the notebook to here.
+
+    const selectedNotebookSub = this.selectedNotebook.subscribe(notebook => {
+      // Happening 4 times for each notebook loaded
+      if (
+        notebook &&
+        notebook.schedulerViewModel == null &&
+        notebook.isSaved() &&
+        !notebook.isHistory()
+      ) {
+        notebook.loadScheduler();
+        if (notebook.viewSchedulerId()) {
+          huePubSub.publish('check.schedules.browser');
+        }
+      }
+    });
+    this.disposals.push(selectedNotebookSub.dispose.bind(selectedNotebookSub));
+
+    const setSelectedNotebookSub = huePubSub.subscribe('jobbrowser.schedule.data', jobs => {
+      if (this.selectedNotebook() && this.selectedNotebook().viewSchedulerId()) {
+        const jobs = jobs.filter(job => this.selectedNotebook().viewSchedulerId() === job.id);
+        this.selectedNotebook().isSchedulerJobRunning(
+          jobs.length > 0 && jobs[0].apiStatus === 'RUNNING'
+        );
+      }
+    });
+    this.disposals.push(setSelectedNotebookSub.remove.bind(setSelectedNotebookSub));
+
+    // Hue 3
+    const setSelectedNotebookSub3 = huePubSub.subscribe(
+      'set.selected.notebook',
+      this.selectedNotebook
+    );
+    this.disposals.push(setSelectedNotebookSub3.remove.bind(setSelectedNotebookSub3));
+
+    const selectedNotebookChangedSub = huePubSub.subscribe(
+      'selected.notebook.changed',
+      this.selectedNotebook
+    );
+    this.disposals.push(selectedNotebookChangedSub.remove.bind(selectedNotebookChangedSub));
+    huePubSub.publish('get.selected.notebook');
+
+    // Hue 4
+    const currentAppSub = huePubSub.subscribe('set.current.app.view.model', viewModel => {
+      if (viewModel.selectedNotebook) {
+        if (viewModel.selectedNotebook()) {
+          this.selectedNotebook(viewModel.selectedNotebook());
+        } else {
+          const subscription = viewModel.selectedNotebook.subscribe(notebook => {
+            this.selectedNotebook(notebook);
+            subscription.dispose();
+          });
+        }
+      } else {
+        this.selectedNotebook(null);
+      }
+    });
+    this.disposals.push(currentAppSub.remove.bind(currentAppSub));
+  }
+
+  dispose() {
+    this.disposals.forEach(dispose => {
+      dispose();
+    });
+  }
+}
+
+let instance;
+
+const viewModelFactory = {
+  createViewModel: () => {
+    if (!instance) {
+      instance = new AssistSchedulePanel();
+    }
+    return instance;
+  }
+};
+
+componentUtils.registerComponent('assist-schedule-panel', viewModelFactory, TEMPLATE);

+ 238 - 0
desktop/core/src/desktop/js/ko/components/assist/ko.rightAssistPanel.js

@@ -0,0 +1,238 @@
+// 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 ko from 'knockout';
+
+import apiHelper from 'api/apiHelper';
+import componentUtils from 'ko/components/componentUtils';
+import huePubSub from 'utils/huePubSub';
+import I18n from 'utils/i18n';
+
+const EDITOR_ASSISTANT_TAB = 'editorAssistant';
+const DASHBOARD_ASSISTANT_TAB = 'dashboardAssistant';
+const FUNCTIONS_TAB = 'functions';
+const SCHEDULES_TAB = 'schedules';
+const LANG_REF_TAB = 'langRef';
+
+const TEMPLATE = `
+  <div class="right-assist-tabs" data-bind="splitFlexDraggable : {
+      containerSelector: '.content-wrapper',
+      sidePanelSelector: '.right-panel',
+      sidePanelVisible: visible,
+      orientation: 'right',
+      onPosition: function() { huePubSub.publish('split.draggable.position') }
+    }">
+    <div class="right-assist-tab" data-bind="visible: editorAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${I18n(
+      'Assistant'
+    )}" data-bind="css: { 'blue' : activeTab() === 'editorAssistant' }, tooltip: { placement: 'left' }, click: editorAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
+    <div class="right-assist-tab" data-bind="visible: dashboardAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${I18n(
+      'Assistant'
+    )}" data-bind="css: { 'blue' : activeTab() === 'dashboardAssistant' }, tooltip: { placement: 'left' }, click: dashboardAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
+    <div class="right-assist-tab" data-bind="visible: functionsTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${I18n(
+      'Functions'
+    )}" data-bind="css: { 'blue' : activeTab() === 'functions' }, tooltip: { placement: 'left' }, click: functionsTabClick"><i class="fa fa-fw fa-superscript"></i></a></div>
+    <div class="right-assist-tab" data-bind="visible: langRefTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${I18n(
+      'Language Reference'
+    )}" data-bind="css: { 'blue' : activeTab() === 'langRef' }, tooltip: { placement: 'left' }, click: langRefTabClick"><i class="fa fa-fw fa-book"></i></a></div>
+    <div class="right-assist-tab" data-bind="visible: schedulesTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${I18n(
+      'Schedule'
+    )}" data-bind="css: { 'blue' : activeTab() === 'schedules' }, tooltip: { placement: 'left' }, click: schedulesTabClick"><i class="fa fa-fw fa-calendar"></i></a></div>
+  </div>
+
+  <!-- ko if: visible -->
+  <div class="right-assist-contents">
+    <!-- ko if: editorAssistantTabAvailable-->
+    <div data-bind="component: { name: 'assist-editor-context-panel', params: { activeTab: activeTab, sourceType: sourceType } }, visible: activeTab() === 'editorAssistant'"></div>
+    <!-- /ko -->
+
+    <!-- ko if: functionsTabAvailable -->
+    <div data-bind="component: { name: 'assist-functions-panel' }, visible: activeTab() === 'functions'"></div>
+    <!-- /ko -->
+
+    <!-- ko if: langRefTabAvailable -->
+    <div data-bind="component: { name: 'assist-language-reference-panel' }, visible: activeTab() === 'langRef'"></div>
+    <!-- /ko -->
+
+    <!-- ko if: dashboardAssistantTabAvailable -->
+    <div data-bind="component: { name: 'assist-dashboard-panel' }, visible: activeTab() === 'dashboardAssistant'"></div>
+    <!-- /ko -->
+
+    <div data-bind="component: { name: 'assist-schedule-panel' }, visible: activeTab() === 'schedules'" style="display:none;"></div>
+  </div>
+  <!-- /ko -->
+`;
+
+class RightAssistPanel {
+  constructor(params) {
+    this.disposals = [];
+
+    this.activeTab = ko.observable();
+    this.visible = params.visible;
+    this.sourceType = ko.observable();
+
+    this.editorAssistantTabAvailable = ko.observable(false);
+    this.dashboardAssistantTabAvailable = ko.observable(false);
+    this.functionsTabAvailable = ko.observable(false);
+    this.langRefTabAvailable = ko.observable(false);
+    this.schedulesTabAvailable = ko.observable(false);
+
+    this.lastActiveTabEditor = apiHelper.withTotalStorage(
+      'assist',
+      'last.open.right.panel',
+      ko.observable(),
+      EDITOR_ASSISTANT_TAB
+    );
+    this.lastActiveTabDashboard = apiHelper.withTotalStorage(
+      'assist',
+      'last.open.right.panel.dashboard',
+      ko.observable(),
+      DASHBOARD_ASSISTANT_TAB
+    );
+
+    huePubSub.subscribe('assist.highlight.risk.suggestions', () => {
+      if (this.editorAssistantTabAvailable() && this.activeTab() !== EDITOR_ASSISTANT_TAB) {
+        this.activeTab(EDITOR_ASSISTANT_TAB);
+      }
+    });
+
+    huePubSub.subscribe('assist.lang.ref.show.topic', targetTopic => {
+      huePubSub.publish('right.assist.show');
+      if (this.langRefTabAvailable() && this.activeTab() !== LANG_REF_TAB) {
+        this.activeTab(LANG_REF_TAB);
+      }
+      huePubSub.publish('assist.lang.ref.panel.show.topic', targetTopic);
+    });
+
+    const updateTabs = () => {
+      if (!this.visible()) {
+        this.activeTab(undefined);
+        return;
+      }
+      if (this.lastActiveTabEditor() === FUNCTIONS_TAB && this.functionsTabAvailable()) {
+        this.activeTab(FUNCTIONS_TAB);
+      } else if (this.lastActiveTabEditor() === SCHEDULES_TAB && this.schedulesTabAvailable()) {
+        this.activeTab(SCHEDULES_TAB);
+      } else if (this.lastActiveTabEditor() === LANG_REF_TAB && this.langRefTabAvailable()) {
+        this.activeTab(LANG_REF_TAB);
+      } else if (this.editorAssistantTabAvailable()) {
+        this.activeTab(EDITOR_ASSISTANT_TAB);
+      } else if (this.functionsTabAvailable()) {
+        this.activeTab(FUNCTIONS_TAB);
+      } else if (this.schedulesTabAvailable()) {
+        this.activeTab(SCHEDULES_TAB);
+      } else if (this.dashboardAssistantTabAvailable()) {
+        this.activeTab(DASHBOARD_ASSISTANT_TAB);
+      } else {
+        this.activeTab(undefined);
+      }
+    };
+
+    const updateContentsForType = (type, isSqlDialect) => {
+      this.sourceType(type);
+
+      // TODO: Get these dynamically from langref and functions modules when moved to webpack
+      this.functionsTabAvailable(type === 'hive' || type === 'impala' || type === 'pig');
+      this.langRefTabAvailable(type === 'hive' || type === 'impala');
+      this.editorAssistantTabAvailable(
+        (!window.IS_EMBEDDED || window.EMBEDDED_ASSISTANT_ENABLED) && isSqlDialect
+      );
+      this.dashboardAssistantTabAvailable(type === 'dashboard');
+      this.schedulesTabAvailable(false);
+      if (type !== 'dashboard') {
+        if (window.ENABLE_QUERY_SCHEDULING) {
+          huePubSub.subscribeOnce('set.current.app.view.model', viewModel => {
+            // Async
+            this.schedulesTabAvailable(!!viewModel.selectedNotebook);
+            updateTabs();
+          });
+          huePubSub.publish('get.current.app.view.model');
+        } else {
+          this.schedulesTabAvailable(false);
+        }
+      }
+      updateTabs();
+    };
+
+    const snippetTypeSub = huePubSub.subscribe('active.snippet.type.changed', details => {
+      updateContentsForType(details.type, details.isSqlDialect);
+    });
+    this.disposals.push(snippetTypeSub.remove.bind(snippetTypeSub));
+
+    huePubSub.subscribe('set.current.app.name', appName => {
+      if (appName === 'dashboard') {
+        updateContentsForType(appName, false);
+      }
+    });
+    huePubSub.publish('get.current.app.name');
+    updateTabs();
+  }
+
+  switchTab(tabName) {
+    if (this.activeTab() === tabName) {
+      this.visible(false);
+      this.activeTab(undefined);
+    } else {
+      this.activeTab(tabName);
+      if (!this.visible()) {
+        this.visible(true);
+      }
+    }
+  }
+
+  editorAssistantTabClick() {
+    this.lastActiveTabEditor(EDITOR_ASSISTANT_TAB);
+    this.switchTab(EDITOR_ASSISTANT_TAB);
+  }
+
+  dashboardAssistantTabClick() {
+    this.lastActiveTabDashboard(DASHBOARD_ASSISTANT_TAB);
+    this.switchTab(DASHBOARD_ASSISTANT_TAB);
+  }
+
+  functionsTabClick() {
+    this.lastActiveTabEditor(FUNCTIONS_TAB);
+    this.switchTab(FUNCTIONS_TAB);
+  }
+
+  langRefTabClick() {
+    this.lastActiveTabEditor(LANG_REF_TAB);
+    this.switchTab(LANG_REF_TAB);
+  }
+
+  schedulesTabClick() {
+    this.lastActiveTabEditor(SCHEDULES_TAB);
+    this.switchTab(SCHEDULES_TAB);
+  }
+
+  dispose() {
+    this.disposals.forEach(dispose => {
+      dispose();
+    });
+  }
+}
+
+let instance;
+
+const viewModelFactory = {
+  createViewModel: params => {
+    if (!instance) {
+      instance = new RightAssistPanel(params);
+    }
+    return instance;
+  }
+};
+
+componentUtils.registerComponent('right-assist-panel', viewModelFactory, TEMPLATE);

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

@@ -127,6 +127,7 @@ import 'ko/bindings/ko.verticalSlide';
 import 'ko/bindings/ko.visibleOnHover';
 import 'ko/bindings/ko.visibleOnHover';
 
 
 import 'ko/components/assist/ko.assistAdlsPanel';
 import 'ko/components/assist/ko.assistAdlsPanel';
+import 'ko/components/assist/ko.assistDashboardPanel';
 import 'ko/components/assist/ko.assistDbPanel';
 import 'ko/components/assist/ko.assistDbPanel';
 import 'ko/components/assist/ko.assistDocumentsPanel';
 import 'ko/components/assist/ko.assistDocumentsPanel';
 import 'ko/components/assist/ko.assistEditorContextPanel';
 import 'ko/components/assist/ko.assistEditorContextPanel';
@@ -137,6 +138,8 @@ import 'ko/components/assist/ko.assistHdfsPanel';
 import 'ko/components/assist/ko.assistLangRefPanel';
 import 'ko/components/assist/ko.assistLangRefPanel';
 import 'ko/components/assist/ko.assistPanel';
 import 'ko/components/assist/ko.assistPanel';
 import 'ko/components/assist/ko.assistS3Panel';
 import 'ko/components/assist/ko.assistS3Panel';
+import 'ko/components/assist/ko.assistSchedulePanel';
+import 'ko/components/assist/ko.rightAssistPanel';
 import 'ko/components/contextPopover/ko.contextPopover';
 import 'ko/components/contextPopover/ko.contextPopover';
 import 'ko/components/simpleAceEditor/ko.simpleAceEditor';
 import 'ko/components/simpleAceEditor/ko.simpleAceEditor';
 import 'ko/components/ko.appSwitcher';
 import 'ko/components/ko.appSwitcher';

+ 0 - 468
desktop/core/src/desktop/templates/assist.mako

@@ -1,468 +0,0 @@
-## 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.
-
-<%!
-from django.utils.translation import ugettext as _
-
-from dashboard.conf import HAS_SQL_ENABLED
-from filebrowser.conf import SHOW_UPLOAD_BUTTON
-from metadata.conf import OPTIMIZER
-from metastore.conf import ENABLE_NEW_CREATE_TABLE
-from notebook.conf import ENABLE_QUERY_BUILDER, ENABLE_QUERY_SCHEDULING
-
-from desktop import appmanager
-from desktop import conf
-from desktop.conf import IS_EMBEDDED, USE_NEW_SIDE_PANELS, VCS
-from desktop.lib.i18n import smart_unicode
-from desktop.views import _ko
-%>
-
-
-
-<%def name="assistPanel(is_s3_enabled=False)">
-  
-  <script type="text/javascript">
-
-
-    (function () {
-
-    })();
-  </script>
-
-  <script type="text/html" id="schedule-panel-template">
-    <div class="assist-inner-panel">
-      <div class="assist-flex-panel">
-        <!-- ko if: selectedNotebook() && selectedNotebook().isBatchable() -->
-        <!-- ko with: selectedNotebook() -->
-        <div class="tab-pane" id="scheduleTab">
-          <!-- ko ifnot: isSaved() && ! isHistory() -->
-          ${ _('Query needs to be saved.') }
-          <!-- /ko -->
-          <!-- ko if: isSaved() && ! isHistory() -->
-            <!-- ko if: schedulerViewModelIsLoaded() && schedulerViewModel.coordinator.isDirty() -->
-            <a data-bind="click: saveScheduler" href="javascript: void(0);">${ _('Save changes') }</a>
-            <!-- /ko -->
-            <!-- ko if: schedulerViewModelIsLoaded() && ! schedulerViewModel.coordinator.isDirty() && (! viewSchedulerId() || isSchedulerJobRunning() == false )-->
-            <a data-bind="click: showSubmitPopup" href="javascript: void(0);">${ _('Start') }</a>
-            <!-- /ko -->
-            <!-- ko if: schedulerViewModelIsLoaded() && viewSchedulerId()-->
-            <a data-bind="click: function() { huePubSub.publish('show.jobs.panel', {id: viewSchedulerId(), interface: 'schedules'}) }, clickBubble: false" href="javascript: void(0);">
-              ${ _('View') }
-            </a>
-            <!-- ko if: isSchedulerJobRunning() -->
-              ${ _("Running")}
-            <!-- /ko -->
-            <!-- ko if: isSchedulerJobRunning() == false -->
-              ${ _("Stopped")}
-            <!-- /ko -->
-          <!-- /ko -->
-          <!-- /ko -->
-          <br>
-          <br>
-          <div id="schedulerEditor"></div>
-        </div>
-        <!-- /ko -->
-        <!-- /ko -->
-      </div>
-    </div>
-  </script>
-
-  <script type="text/javascript">
-    (function () {
-      function SchedulePanel(params) {
-        var self = this;
-        self.disposals = [];
-        self.selectedNotebook = ko.observable();
-
-        // TODO: Move all the scheduler logic out of the notebook to here.
-
-        var selectedNotebookSub = self.selectedNotebook.subscribe(function (notebook) { // Happening 4 times for each notebook loaded
-          if (notebook && notebook.schedulerViewModel == null && notebook.isSaved() && ! notebook.isHistory()) {
-            notebook.loadScheduler();
-            if (notebook.viewSchedulerId()) {
-              huePubSub.publish('check.schedules.browser');
-            }
-          }
-        });
-        self.disposals.push(selectedNotebookSub.dispose.bind(selectedNotebookSub));
-
-        var setSelectedNotebookSub = huePubSub.subscribe('jobbrowser.schedule.data', function (jobs) {
-          if (self.selectedNotebook() && self.selectedNotebook().viewSchedulerId()) {
-            var _job = $.grep(jobs, function (job) {
-              return self.selectedNotebook().viewSchedulerId() == job.id;
-            });
-            self.selectedNotebook().isSchedulerJobRunning(_job.length > 0 && _job[0].apiStatus == 'RUNNING');
-          }
-        });
-        self.disposals.push(setSelectedNotebookSub.remove.bind(setSelectedNotebookSub));
-
-        // Hue 3
-        var setSelectedNotebookSub = huePubSub.subscribe('set.selected.notebook', self.selectedNotebook);
-        self.disposals.push(setSelectedNotebookSub.remove.bind(setSelectedNotebookSub));
-        var selectedNotebookChangedSub = huePubSub.subscribe('selected.notebook.changed', self.selectedNotebook);
-        self.disposals.push(selectedNotebookChangedSub.remove.bind(selectedNotebookChangedSub));
-        huePubSub.publish('get.selected.notebook');
-
-        // Hue 4
-        var currentAppSub = huePubSub.subscribe('set.current.app.view.model', function (viewModel) {
-          if (viewModel.selectedNotebook) {
-            if (viewModel.selectedNotebook()) {
-              self.selectedNotebook(viewModel.selectedNotebook());
-            } else {
-              var subscription = viewModel.selectedNotebook.subscribe(function (notebook) {
-                self.selectedNotebook(notebook);
-                subscription.dispose();
-              });
-            }
-          } else {
-            self.selectedNotebook(null);
-          }
-        });
-        self.disposals.push(currentAppSub.remove.bind(currentAppSub));
-      }
-
-      SchedulePanel.prototype.dispose = function () {
-        var self = this;
-        self.disposals.forEach(function (dispose) {
-          dispose();
-        })
-      };
-
-      ko.components.register('schedule-panel', {
-        viewModel: SchedulePanel,
-        template: { element: 'schedule-panel-template' }
-      });
-    })();
-  </script>
-
-  <script type="text/javascript">
-    (function () {
-      function DashboardAssistantPanel(params) {
-        var self = this;
-
-        self.disposals = [];
-        self.isSolr = ko.observable(true);
-
-        self.showRisks = ko.observable(false);
-
-        self.filter = {
-          querySpec: ko.observable({
-            query: '',
-            facets: {},
-            text: []
-          }).extend({ rateLimit: 300 })
-        };
-
-        self.sourceType = ko.observable('solr');
-
-        self.activeTables = ko.observableArray();
-
-        self.filteredTables = AssistantUtils.getFilteredTablesPureComputed(self);
-
-        self.someLoading = ko.pureComputed(function () {
-          return self.activeTables().some(function (table) {
-            return table.loading() || (!table.hasEntries() && !table.hasErrors());
-          });
-        });
-
-        var navigationSettings = {
-          showStats: true,
-          rightAssist: true
-        };
-        var i18n = {};
-
-        var activeDashboardCollection = huePubSub.subscribe('set.active.dashboard.collection', function(collection) {
-          var collectionName = collection.name();
-
-          if (!collectionName) {
-            return;
-          }
-
-          self.sourceType = ko.observable(collection.engine());
-
-          var assistDbSource = new AssistDbSource({
-            i18n : i18n,
-            initialNamespace: collection.activeNamespace,
-            initialCompute: collection.activeCompute,
-            type: collection.engine(),
-            name: collection.engine(),
-            nonSqlType: true,
-            navigationSettings: navigationSettings
-          });
-
-          var fakeParentName = collectionName.indexOf('.') > -1 ? collectionName.split('.')[0] : 'default';
-
-          var sourceType = collection.source() === 'query' ? collection.engine() + '-query' : collection.engine();
-
-          dataCatalog.getEntry({
-            sourceType: sourceType,
-            namespace: collection.activeNamespace,
-            compute: collection.activeCompute,
-            path: [ fakeParentName ],
-            definition: { type: 'database' }
-          }).done(function (fakeDbCatalogEntry) {
-            var assistFakeDb = new AssistDbEntry(fakeDbCatalogEntry, null, assistDbSource, self.filter, i18n, navigationSettings);
-            dataCatalog.getEntry({
-              sourceType: sourceType,
-              namespace: collection.activeNamespace,
-              compute: collection.activeCompute,
-              path: [fakeParentName, collectionName.indexOf('.') > -1 ? collectionName.split('.')[1] : collectionName],
-              definition: { type: 'table' }
-            }).done(function (collectionCatalogEntry) {
-              var collectionEntry = new AssistDbEntry(collectionCatalogEntry, assistFakeDb, assistDbSource, self.filter, i18n, navigationSettings);
-              self.activeTables([collectionEntry]);
-
-              if (!collectionEntry.loaded && !collectionEntry.hasErrors() && !collectionEntry.loading()) {
-                collectionEntry.loadEntries(function() { collectionEntry.toggleOpen(); });
-              }
-            });
-          });
-
-          self.autocompleteFromEntries = function (nonPartial, partial) {
-            var added = {};
-            var result = [];
-            var partialLower = partial.toLowerCase();
-            self.activeTables().forEach(function (table) {
-              if (!added[table.catalogEntry.name] && table.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
-                added[table.catalogEntry.name] = true;
-                result.push(nonPartial + partial + table.catalogEntry.name.substring(partial.length))
-              }
-              table.entries().forEach(function (col) {
-                if (!added[col.catalogEntry.name] && col.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
-                  added[col.catalogEntry.name] = true;
-                  result.push(nonPartial + partial + col.catalogEntry.name.substring(partial.length))
-                }
-              })
-            });
-            return result;
-          };
-        });
-
-        self.disposals.push(function () {
-          activeDashboardCollection.remove();
-        });
-      }
-
-      DashboardAssistantPanel.prototype.dispose = function () {
-        var self = this;
-        self.disposals.forEach(function (dispose) {
-          dispose();
-        })
-      };
-
-      ko.components.register('dashboard-assistant-panel', {
-        viewModel: DashboardAssistantPanel,
-        template: { element: 'editor-assistant-panel-template' }
-      });
-    })();
-  </script>
-
-  <script type="text/html" id="right-assist-panel-template">
-    <div class="right-assist-tabs" data-bind="splitFlexDraggable : {
-        containerSelector: '.content-wrapper',
-        sidePanelSelector: '.right-panel',
-        sidePanelVisible: visible,
-        orientation: 'right',
-        onPosition: function() { huePubSub.publish('split.draggable.position') }
-      }">
-      <div class="right-assist-tab" data-bind="visible: editorAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Assistant') }" data-bind="css: { 'blue' : activeTab() === 'editorAssistant' }, tooltip: { placement: 'left' }, click: editorAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
-      <div class="right-assist-tab" data-bind="visible: dashboardAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Assistant') }" data-bind="css: { 'blue' : activeTab() === 'dashboardAssistant' }, tooltip: { placement: 'left' }, click: dashboardAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
-      <div class="right-assist-tab" data-bind="visible: functionsTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Functions') }" data-bind="css: { 'blue' : activeTab() === 'functions' }, tooltip: { placement: 'left' }, click: functionsTabClick"><i class="fa fa-fw fa-superscript"></i></a></div>
-      <div class="right-assist-tab" data-bind="visible: langRefTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Language Reference') }" data-bind="css: { 'blue' : activeTab() === 'langRef' }, tooltip: { placement: 'left' }, click: langRefTabClick"><i class="fa fa-fw fa-book"></i></a></div>
-      <div class="right-assist-tab" data-bind="visible: schedulesTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Schedule') }" data-bind="css: { 'blue' : activeTab() === 'schedules' }, tooltip: { placement: 'left' }, click: schedulesTabClick"><i class="fa fa-fw fa-calendar"></i></a></div>
-    </div>
-
-    <!-- ko if: visible -->
-    <div class="right-assist-contents">
-      <!-- ko if: editorAssistantTabAvailable-->
-      <div data-bind="component: { name: 'assist-editor-context-panel', params: { activeTab: activeTab, sourceType: sourceType } }, visible: activeTab() === 'editorAssistant'"></div>
-      <!-- /ko -->
-
-      <!-- ko if: functionsTabAvailable -->
-      <div data-bind="component: { name: 'assist-functions-panel' }, visible: activeTab() === 'functions'"></div>
-      <!-- /ko -->
-
-      <!-- ko if: langRefTabAvailable -->
-      <div data-bind="component: { name: 'assist-language-reference-panel' }, visible: activeTab() === 'langRef'"></div>
-      <!-- /ko -->
-
-      <!-- ko if: dashboardAssistantTabAvailable -->
-      <div data-bind="component: { name: 'dashboard-assistant-panel' }, visible: activeTab() === 'dashboardAssistant'"></div>
-      <!-- /ko -->
-
-      ## TODO: Switch to if: when loadSchedules from notebook.ko.js has been moved to the schedule-panel component
-      <div data-bind="component: { name: 'schedule-panel' }, visible: activeTab() === 'schedules'" style="display:none;"></div>
-    </div>
-    <!-- /ko -->
-  </script>
-
-  <script type="text/javascript">
-    (function () {
-
-      var EDITOR_ASSISTANT_TAB = 'editorAssistant';
-      var DASHBOARD_ASSISTANT_TAB = 'dashboardAssistant';
-      var FUNCTIONS_TAB = 'functions';
-      var SCHEDULES_TAB = 'schedules';
-      var LANG_REF_TAB = 'langRef';
-
-      function RightAssistPanel(params) {
-        var self = this;
-        self.disposals = [];
-
-        self.activeTab = ko.observable();
-        self.visible = params.visible;
-        self.sourceType = ko.observable();
-
-        self.editorAssistantTabAvailable = ko.observable(false);
-        self.dashboardAssistantTabAvailable = ko.observable(false);
-        self.functionsTabAvailable = ko.observable(false);
-        self.langRefTabAvailable = ko.observable(false);
-        self.schedulesTabAvailable = ko.observable(false);
-
-        self.lastActiveTabEditor = window.apiHelper.withTotalStorage('assist', 'last.open.right.panel', ko.observable(), EDITOR_ASSISTANT_TAB);
-        self.lastActiveTabDashboard = window.apiHelper.withTotalStorage('assist', 'last.open.right.panel.dashboard', ko.observable(), DASHBOARD_ASSISTANT_TAB);
-
-        huePubSub.subscribe('assist.highlight.risk.suggestions', function () {
-          if (self.editorAssistantTabAvailable() && self.activeTab() !== EDITOR_ASSISTANT_TAB) {
-            self.activeTab(EDITOR_ASSISTANT_TAB);
-          }
-        });
-
-        huePubSub.subscribe('assist.lang.ref.show.topic', function (targetTopic) {
-          huePubSub.publish('right.assist.show');
-          if (self.langRefTabAvailable() && self.activeTab() !== LANG_REF_TAB) {
-            self.activeTab(LANG_REF_TAB);
-          }
-          huePubSub.publish('assist.lang.ref.panel.show.topic', targetTopic)
-        });
-
-        var updateTabs = function () {
-          if (!self.visible()) {
-            self.activeTab(undefined);
-            return;
-          }
-          if (self.lastActiveTabEditor() === FUNCTIONS_TAB && self.functionsTabAvailable()) {
-            self.activeTab(FUNCTIONS_TAB);
-          } else if (self.lastActiveTabEditor() === SCHEDULES_TAB && self.schedulesTabAvailable()) {
-            self.activeTab(SCHEDULES_TAB);
-          } else if (self.lastActiveTabEditor() === LANG_REF_TAB && self.langRefTabAvailable()) {
-            self.activeTab(LANG_REF_TAB);
-          } else if (self.editorAssistantTabAvailable()) {
-            self.activeTab(EDITOR_ASSISTANT_TAB);
-          } else if (self.functionsTabAvailable()) {
-            self.activeTab(FUNCTIONS_TAB);
-          } else if (self.schedulesTabAvailable()) {
-            self.activeTab(SCHEDULES_TAB);
-          } else if (self.dashboardAssistantTabAvailable()) {
-            self.activeTab(DASHBOARD_ASSISTANT_TAB);
-          } else {
-            self.activeTab(undefined);
-          }
-        };
-
-        var updateContentsForType = function (type, isSqlDialect) {
-          self.sourceType(type);
-
-          // TODO: Get these dynamically from langref and functions modules when moved to webpack
-          self.functionsTabAvailable(type === 'hive' || type === 'impala' || type === 'pig');
-          self.langRefTabAvailable(type === 'hive' || type === 'impala');
-          self.editorAssistantTabAvailable((!window.IS_EMBEDDED || window.EMBEDDED_ASSISTANT_ENABLED) && isSqlDialect);
-          self.dashboardAssistantTabAvailable(type === 'dashboard');
-          self.schedulesTabAvailable(false);
-          if (type !== 'dashboard') {
-            if ('${ ENABLE_QUERY_SCHEDULING.get() }' === 'True') {
-              huePubSub.subscribeOnce('set.current.app.view.model', function (viewModel) {
-                // Async
-                self.schedulesTabAvailable(!!viewModel.selectedNotebook);
-                updateTabs();
-              });
-              huePubSub.publish('get.current.app.view.model');
-            } else {
-              self.schedulesTabAvailable(false);
-            }
-          }
-          updateTabs();
-        };
-
-        var snippetTypeSub = huePubSub.subscribe('active.snippet.type.changed', function (details) { updateContentsForType(details.type, details.isSqlDialect) });
-        self.disposals.push(snippetTypeSub.remove.bind(snippetTypeSub));
-
-        huePubSub.subscribe('set.current.app.name', function (appName) {
-          if (appName === 'dashboard') {
-            updateContentsForType(appName, false);
-          }
-        });
-        huePubSub.publish('get.current.app.name');
-        updateTabs();
-      }
-
-      RightAssistPanel.prototype.switchTab = function (tabName) {
-        var self = this;
-        if (self.activeTab() === tabName) {
-          self.visible(false);
-          self.activeTab(undefined);
-        } else {
-          self.activeTab(tabName);
-          if (!self.visible()) {
-            self.visible(true);
-          }
-        }
-      };
-
-      RightAssistPanel.prototype.editorAssistantTabClick = function () {
-        var self = this;
-        self.lastActiveTabEditor(EDITOR_ASSISTANT_TAB);
-        self.switchTab(EDITOR_ASSISTANT_TAB);
-      };
-
-      RightAssistPanel.prototype.dashboardAssistantTabClick = function () {
-        var self = this;
-        self.lastActiveTabDashboard(DASHBOARD_ASSISTANT_TAB);
-        self.switchTab(DASHBOARD_ASSISTANT_TAB);
-      };
-
-      RightAssistPanel.prototype.functionsTabClick = function () {
-        var self = this;
-        self.lastActiveTabEditor(FUNCTIONS_TAB);
-        self.switchTab(FUNCTIONS_TAB);
-      };
-
-      RightAssistPanel.prototype.langRefTabClick = function () {
-        var self = this;
-        self.lastActiveTabEditor(LANG_REF_TAB);
-        self.switchTab(LANG_REF_TAB);
-      };
-
-      RightAssistPanel.prototype.schedulesTabClick = function () {
-        var self = this;
-        self.lastActiveTabEditor(SCHEDULES_TAB);
-        self.switchTab(SCHEDULES_TAB);
-      };
-
-      RightAssistPanel.prototype.dispose = function () {
-        var self = this;
-        self.disposals.forEach(function (dispose) {
-          dispose();
-        })
-      };
-
-      ko.components.register('right-assist-panel', {
-        viewModel: RightAssistPanel,
-        template: { element: 'right-assist-panel-template' }
-      });
-    })();
-  </script>
-</%def>

+ 0 - 4
desktop/core/src/desktop/templates/assist_m.mako

@@ -19,14 +19,10 @@ from desktop.views import commonheader_m, commonfooter_m
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="assist.mako" />
-
 ${ commonheader_m(_('Assist'), 'assist', user, request) | n,unicode }
 ${ commonheader_m(_('Assist'), 'assist', user, request) | n,unicode }
 
 
 <script src="${ static('metastore/js/metastore.ko.js') }"></script>
 <script src="${ static('metastore/js/metastore.ko.js') }"></script>
 
 
-${ assist.assistPanel() }
-
 <style type="text/css">
 <style type="text/css">
   .assist {
   .assist {
     margin-left: -10px;
     margin-left: -10px;

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

@@ -136,6 +136,7 @@
     'Apps': '${ _('Apps') }',
     'Apps': '${ _('Apps') }',
     'Are you sure you want to clear the task history?': '${ _('Are you sure you want to clear the task history?') }',
     'Are you sure you want to clear the task history?': '${ _('Are you sure you want to clear the task history?') }',
     'Assist': '${ _('Assist') }',
     'Assist': '${ _('Assist') }',
+    'Assistant': '${ _('Assistant') }',
     'at cursor': '${ _('at cursor') }',
     'at cursor': '${ _('at cursor') }',
     'Back': '${_('Back')}',
     'Back': '${_('Back')}',
     'Browse column privileges': '${_('Browse column privileges')}',
     'Browse column privileges': '${_('Browse column privileges')}',
@@ -262,6 +263,7 @@
     'Key': '${ _('Key') }',
     'Key': '${ _('Key') }',
     'keyword': '${ _('keyword') }',
     'keyword': '${ _('keyword') }',
     'Keywords': '${ _('Keywords') }',
     'Keywords': '${ _('Keywords') }',
+    'Language Reference': '${ _('Language Reference') }',
     'Loading metrics...': '${ _('Loading metrics...') }',
     'Loading metrics...': '${ _('Loading metrics...') }',
     'Lock this row': '${_('Lock this row')}',
     'Lock this row': '${_('Lock this row')}',
     'MapReduce Job': '${_('MapReduce Job')}',
     'MapReduce Job': '${_('MapReduce Job')}',
@@ -349,6 +351,7 @@
     'Query Analysis': '${ _('Query Analysis') }',
     'Query Analysis': '${ _('Query Analysis') }',
     'Query browser': '${ _('Query browser') }',
     'Query browser': '${ _('Query browser') }',
     'Query failed': '${ _('Query failed') }',
     'Query failed': '${ _('Query failed') }',
+    'Query needs to be saved.': '${ _('Query needs to be saved.') }',
     'Query requires a select or aggregate.': '${ _('Query requires a select or aggregate.') }',
     'Query requires a select or aggregate.': '${ _('Query requires a select or aggregate.') }',
     'Query running': '${ _('Query running') }',
     'Query running': '${ _('Query running') }',
     'queued': '${ _('queued') }',
     'queued': '${ _('queued') }',
@@ -359,11 +362,13 @@
     'Result expired': '${ _('Result expired') }',
     'Result expired': '${ _('Result expired') }',
     'result(s) copied to the clipboard' : '${ _('result(s) copied to the clipboard') }',
     'result(s) copied to the clipboard' : '${ _('result(s) copied to the clipboard') }',
     'Risks': '${ _('Risks') }',
     'Risks': '${ _('Risks') }',
+    'Running': '${ _('Running') }',
     'sample query': '${ _('sample query') }',
     'sample query': '${ _('sample query') }',
     'Sample': '${ _('Sample') }',
     'Sample': '${ _('Sample') }',
     'sample': '${ _('sample') }',
     'sample': '${ _('sample') }',
     'Samples': '${ _('Samples') }',
     'Samples': '${ _('Samples') }',
     'Save': '${ _('Save') }',
     'Save': '${ _('Save') }',
+    'Save changes': '${ _('Save changes') }',
     'Schedule': '${ _('Schedule') }',
     'Schedule': '${ _('Schedule') }',
     'Search Dashboard': '${_('Search Dashboard')}',
     'Search Dashboard': '${_('Search Dashboard')}',
     'Search data and saved documents...': '${ _('Search data and saved documents...') }',
     'Search data and saved documents...': '${ _('Search data and saved documents...') }',
@@ -390,8 +395,10 @@
     'Sources': '${ _('Sources') }',
     'Sources': '${ _('Sources') }',
     'Statement': '${ _('Statement') }',
     'Statement': '${ _('Statement') }',
     'Spark Job': '${_('Spark Job')}',
     'Spark Job': '${_('Spark Job')}',
+    'Start': '${_('Start')}',
     'Starting': '${_('Starting')}',
     'Starting': '${_('Starting')}',
     'Stats': '${_('Stats')}',
     'Stats': '${_('Stats')}',
+    'Stopped': '${_('Stopped')}',
     'Summary': '${_('Summary')}',
     'Summary': '${_('Summary')}',
     'Table Browser': '${ _('Table Browser') }',
     'Table Browser': '${ _('Table Browser') }',
     'table': '${ _('table') }',
     'table': '${ _('table') }',
@@ -426,6 +433,7 @@
     'Values': '${ _('Values') }',
     'Values': '${ _('Values') }',
     'variable': '${ _('variable') }',
     'variable': '${ _('variable') }',
     'Variables': '${ _('Variables') }',
     'Variables': '${ _('Variables') }',
+    'View': '${ _('View') }',
     'view': '${ _('view') }',
     'view': '${ _('view') }',
     'Views': '${ _('Views') }',
     'Views': '${ _('Views') }',
     'virtual': '${ _('virtual') }',
     'virtual': '${ _('virtual') }',

+ 0 - 2
desktop/core/src/desktop/templates/home2.mako

@@ -20,12 +20,10 @@
   from desktop import conf
   from desktop import conf
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="common_home" file="/common_home.mako" />
 <%namespace name="common_home" file="/common_home.mako" />
 
 
 %if not is_embeddable:
 %if not is_embeddable:
 ${ commonheader(_('Welcome Home'), "home", user, request) | n,unicode }
 ${ commonheader(_('Welcome Home'), "home", user, request) | n,unicode }
-${ assist.assistPanel() }
 %endif
 %endif
 
 
 ${ common_home.homeJSModels(is_embeddable) }
 ${ common_home.homeJSModels(is_embeddable) }

+ 0 - 3
desktop/core/src/desktop/templates/hue.mako

@@ -32,7 +32,6 @@
   from webpack_loader.templatetags.webpack_loader import render_bundle
   from webpack_loader.templatetags.webpack_loader import render_bundle
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="hueIcons" file="/hue_icons.mako" />
 <%namespace name="hueIcons" file="/hue_icons.mako" />
 <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
 <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
 
 
@@ -504,8 +503,6 @@ ${ commonHeaderFooterComponents.header_pollers(user, is_s3_enabled, apps) }
 ## clusterConfig makes an Ajax call so it needs to be after commonHeaderFooterComponents
 ## clusterConfig makes an Ajax call so it needs to be after commonHeaderFooterComponents
 <script src="${ static('desktop/js/clusterConfig.js') }"></script>
 <script src="${ static('desktop/js/clusterConfig.js') }"></script>
 
 
-${ assist.assistPanel() }
-
 % if request is not None:
 % if request is not None:
 ${ smart_unicode(login_modal(request).content) | n,unicode }
 ${ smart_unicode(login_modal(request).content) | n,unicode }
 % endif
 % endif

+ 0 - 3
desktop/libs/indexer/src/indexer/templates/importer.mako

@@ -26,7 +26,6 @@
 %>
 %>
 
 
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
-<%namespace name="assist" file="/assist.mako" />
 
 
 %if not is_embeddable:
 %if not is_embeddable:
 ${ commonheader(_("Importer"), "indexer", user, request, "60px") | n,unicode }
 ${ commonheader(_("Importer"), "indexer", user, request, "60px") | n,unicode }
@@ -35,8 +34,6 @@ ${ commonheader(_("Importer"), "indexer", user, request, "60px") | n,unicode }
 
 
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
-${ assist.assistPanel() }
-
 %endif
 %endif
 
 
 <link rel="stylesheet" href="${ static('indexer/css/importer.css') }" type="text/css">
 <link rel="stylesheet" href="${ static('indexer/css/importer.css') }" type="text/css">

+ 0 - 3
desktop/libs/indexer/src/indexer/templates/indexer.mako

@@ -22,7 +22,6 @@
 %>
 %>
 
 
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
-<%namespace name="assist" file="/assist.mako" />
 
 
 %if not is_embeddable:
 %if not is_embeddable:
 ${ commonheader(_("Solr Indexes"), "search", user, request, "60px") | n,unicode }
 ${ commonheader(_("Solr Indexes"), "search", user, request, "60px") | n,unicode }
@@ -31,8 +30,6 @@ ${ commonheader(_("Solr Indexes"), "search", user, request, "60px") | n,unicode
 
 
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
 <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
-
-${ assist.assistPanel() }
 %endif
 %endif
 
 
 <style type="text/css">
 <style type="text/css">

+ 0 - 3
desktop/libs/indexer/src/indexer/templates/indexes.mako

@@ -21,7 +21,6 @@
   from desktop.views import commonheader, commonfooter, commonshare, commonimportexport, _ko
   from desktop.views import commonheader, commonfooter, commonshare, commonimportexport, _ko
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
 
 
 <%
 <%
@@ -43,8 +42,6 @@ ${ commonheader(_("Index Browser"), "search", user, request, "60px") | n,unicode
   }
   }
 % endif
 % endif
 </style>
 </style>
-
-${ assist.assistPanel() }
 %endif
 %endif
 
 
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }" type="text/css">
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }" type="text/css">

+ 0 - 3
desktop/libs/indexer/src/indexer/templates/topics.mako

@@ -21,7 +21,6 @@
   from desktop.views import commonheader, commonfooter, commonshare, commonimportexport, _ko
   from desktop.views import commonheader, commonfooter, commonshare, commonimportexport, _ko
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
 
 
 <%
 <%
@@ -43,8 +42,6 @@ ${ commonheader(_("Streams Browser"), "search", user, request, "60px") | n,unico
   }
   }
 % endif
 % endif
 </style>
 </style>
-
-${ assist.assistPanel() }
 %endif
 %endif
 
 
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }" type="text/css">
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }" type="text/css">

+ 0 - 2
desktop/libs/notebook/src/notebook/templates/editor.mako

@@ -19,7 +19,6 @@
   from django.utils.translation import ugettext as _
   from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
 <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
@@ -37,7 +36,6 @@ ${ editorComponents.topBar(suffix='editor') }
 ${ editorComponents.commonHTML(is_embeddable=is_embeddable, suffix='editor') }
 ${ editorComponents.commonHTML(is_embeddable=is_embeddable, suffix='editor') }
 
 
 %if not is_embeddable:
 %if not is_embeddable:
-${ assist.assistPanel() }
 ${ configKoComponents.config() }
 ${ configKoComponents.config() }
 ${ notebookKoComponents.aceKeyboardShortcuts() }
 ${ notebookKoComponents.aceKeyboardShortcuts() }
 ${ notebookKoComponents.downloadSnippetResults() }
 ${ notebookKoComponents.downloadSnippetResults() }

+ 0 - 1
desktop/libs/notebook/src/notebook/templates/editor_m.mako

@@ -19,7 +19,6 @@
   from django.utils.translation import ugettext as _
   from django.utils.translation import ugettext as _
   from desktop.views import _ko
   from desktop.views import _ko
 %>
 %>
-<%namespace name="assist" file="/assist.mako" />
 
 
 ${ commonheader_m(editor_type, editor_type, user, request, "68px") | n,unicode }
 ${ commonheader_m(editor_type, editor_type, user, request, "68px") | n,unicode }
 
 

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

@@ -19,7 +19,6 @@
   from django.utils.translation import ugettext as _
   from django.utils.translation import ugettext as _
 %>
 %>
 
 
-<%namespace name="assist" file="/assist.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
 <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
@@ -53,7 +52,6 @@ ${ editorComponents.topBar(suffix='notebook') }
 </%editorComponents:commonHTML>
 </%editorComponents:commonHTML>
 
 
 %if not is_embeddable:
 %if not is_embeddable:
-${ assist.assistPanel() }
 ${ configKoComponents.config() }
 ${ configKoComponents.config() }
 ${ notebookKoComponents.aceKeyboardShortcuts() }
 ${ notebookKoComponents.aceKeyboardShortcuts() }
 ${ notebookKoComponents.downloadSnippetResults() }
 ${ notebookKoComponents.downloadSnippetResults() }