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

[ui-Quick Start] Convert the Quick Start page within administrator server in ReactJS (#4025)

* Quick Start in React

wip

* fixes the api interface error

* Fixes based on review comments

* liniting and review changes

* Fixing isAdmin check

* Changes after the review comments

* Fixing unit tests

* Review comment changes

* test changes

* Test changes

WIP

* Linting issues fixed

* Test changes

* Re review changes

WIP

* fixing nits based on reviews

WIP

WIP

WIP

* Fixing unit tests

WIP

* Fixing the new urls to make them same as the old ones

wip

WIP

* Final review changes

wip

linting

* Review changes

* nit commit

---------

Co-authored-by: Ram Prasad Agarwal <work.ramprasad@gmail.com>
Ananya_Agarwal 7 сар өмнө
parent
commit
4d9bd2162e
22 өөрчлөгдсөн 656 нэмэгдсэн , 615 устгасан
  1. 2 295
      apps/about/src/about/templates/admin_wizard.mako
  2. 0 44
      apps/hive/src/hive/tests.py
  3. 1 1
      desktop/core/src/desktop/api2_tests.py
  4. 1 1
      desktop/core/src/desktop/api_public.py
  5. 5 0
      desktop/core/src/desktop/js/apps/admin/Components/utils.ts
  6. 4 3
      desktop/core/src/desktop/js/apps/admin/Configuration/ConfigurationTab.tsx
  7. 4 3
      desktop/core/src/desktop/js/apps/admin/Metrics/MetricsTab.tsx
  8. 1 1
      desktop/core/src/desktop/js/apps/admin/Metrics/MetricsTable.tsx
  9. 77 0
      desktop/core/src/desktop/js/apps/admin/Overview/Analytics.tsx
  10. 118 0
      desktop/core/src/desktop/js/apps/admin/Overview/ConfigStatus.tsx
  11. 139 0
      desktop/core/src/desktop/js/apps/admin/Overview/Examples.tsx
  12. 87 0
      desktop/core/src/desktop/js/apps/admin/Overview/Overview.scss
  13. 145 0
      desktop/core/src/desktop/js/apps/admin/Overview/OverviewTab.test.tsx
  14. 56 0
      desktop/core/src/desktop/js/apps/admin/Overview/OverviewTab.tsx
  15. 3 0
      desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsHeader.scss
  16. 4 3
      desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsHeader.tsx
  17. 2 2
      desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsTab.tsx
  18. 3 0
      desktop/core/src/desktop/js/reactComponents/imports.js
  19. 3 179
      desktop/core/src/desktop/static/desktop/js/admin-wizard-inline.js
  20. 0 65
      desktop/core/src/desktop/templates/check_config.mako
  21. 0 5
      desktop/core/src/desktop/templates/logs.mako
  22. 1 13
      desktop/core/src/desktop/templates/metrics.mako

+ 2 - 295
apps/about/src/about/templates/admin_wizard.mako

@@ -14,306 +14,13 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 
-<%!
-import sys
-
-from django.urls import reverse
-
-from metadata.conf import OPTIMIZER, has_optimizer
-
-from desktop.auth.backend import is_admin
-from desktop.conf import has_connectors
-from desktop.views import commonheader, commonfooter
-
-if sys.version_info[0] > 2:
-  from django.utils.translation import gettext as _
-else:
-  from django.utils.translation import ugettext as _
-%>
 
 <%namespace name="layout" file="/about_layout.mako" />
 
-% if not is_embeddable:
-  ${ commonheader(_('Quick Start'), "quickstart", user, request, "70px") | n,unicode }
-% endif
-
 ${ layout.menubar(section='quick_start') }
 
-<div class="container-fluid" id="adminWizardComponents">
-  <div class="row-fluid" style="margin-bottom: 100px;">
-    <div>
-      <h1 class="margin-top-20 margin-bottom-30">
-        % if is_admin(user):
-          ${ _('Quick Start') } -
-        % endif
-        <a href="https://gethue.com" target="_blank" title="${ _('Open Hue\'s website in a new tab') }">
-          Hue&trade;
-          ${ version }
-        </a>
-        -
-        Query. Explore. Repeat.
-      </h1>
-
-     % if is_admin(user):
-      <div class="margin-bottom-30">
-         <div class="row-fluid">
-
-           <div class="span2">
-            <ul class="nav nav-pills nav-vertical-pills">
-              <li class="active"><a href="#step1" class="step">${ _('Step 1:') } <i class="fa fa-check"></i> ${ _('Checks') }</a></li>
-              <li><a href="#step2" class="step">${ _('Step 2:') } <i class="fa fa-exchange"></i> ${ _('Connectors') }</a></li>
-              <li><a href="#step3" class="step">${ _('Step 3:') } <i class="fa fa-book"></i> ${ _('Examples') }</a></li>
-              <li><a id="lastStep" href="#step4" class="step">${ _('Step 4:') } <i class="fa fa-group"></i> ${ _('Users') }</a></li>
-            </ul>
-           </div>
-
-          <div class="span10 steps">
-          <div id="step1" class="stepDetails">
-            <div>
-              <h3>${ _('Checking current configuration') }</h3>
-
-              <div id="check-config-section" class="margin-bottom-20">
-                <div class="spinner">
-                  <i class="fa fa-spinner fa-spin" style="font-size: 60px; color: #DDD"></i>
-                </div>
-                <div class="info hide"></div>
-              </div>
-            </div>
-          </div>
-
-          <div id="step2" class="stepDetails hide">
-            <h3>${ _('Add connectors to data services') }</h3>
-
-            % if has_connectors():
-            <span id="connectorCounts">...</span> ${ _('connectors installed') }
-
-            <ul class="unstyled samples margin-top-20">
-              <li>
-                <a href="${ url('desktop.lib.connectors.views.index') }" title="${ _('Open the connector configuration page') }">
-                  <i class="fa fa-plus"></i> ${ _('Add a Database') }
-                </a>
-              </li>
-              <li>
-                <a href="javascript:void(0)" class="installBtn" title="${ _('Install the connector examples') }" data-is-connector="true"
-                  data-loading-text="${ _('Installing...') }" data-sample-url="${ url('connectors.api.install_connector_examples') }">
-                  <i class="fa fa-download"></i> ${ _('Install examples') }
-                </a>
-              </li>
-            </ul>
-            % else:
-              <a href="${ url('desktop.views.dump_config') }" target="_blank">${ _('Configuration') }</a>
-              <br>
-              <a href="https://docs.gethue.com/administrator/configuration/" target="_blank">${ _('Documentation') }</a>
-            % endif
-          </div>
-
-          <div id="step3" class="stepDetails hide">
-            <div>
-              <h3>${ _('Install some data examples') }</h3>
-              <ul class="unstyled samples">
-
-              % if has_connectors():
-                <!-- ko foreach: connectors -->
-                  <!-- ko if: ['hive', 'impala', 'mysql', 'postgresql', 'presto', 'phoenix', 'flink', 'ksql'].indexOf(dialect) != -1 -->
-                  <li>
-                    <a href="javascript:void(0)" data-bind="click: $root.installConnectorDataExample">
-                      <i class="fa fa-download"></i> <span data-bind="text: name"></span>
-                    </a>
-                  </li>
-                  <!-- /ko -->
-                <!-- /ko -->
-
-                <li>
-                  <div id="check-config-section" class="margin-bottom-20" data-bind="visible: isInstallingSample">
-                    <div class="spinner">
-                      <i class="fa fa-spinner fa-spin" style="font-size: 60px; color: #DDD"></i>
-                    </div>
-                  </div>
-                </li>
-              % else:
-                % if 'hive' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('beeswax:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['beeswax'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'impala' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('impala:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['impala'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if has_optimizer() and OPTIMIZER.QUERY_HISTORY_UPLOAD_LIMIT.get() > 0:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Uploading...') }"
-                       data-sample-url="${ url('metadata:upload_history') }" title="${ _('Send and analyze past %s executed queries to provide smarter SQL recommendations') % OPTIMIZER.QUERY_HISTORY_UPLOAD_LIMIT.get() }">
-                      <i class="fa fa-download"></i> ${ _('SQL Query history') }
-                    </a>
-                  </li>
-                % endif
-                % if 'search' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installAllBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('search:install_examples') }" data-sample-data='["log_analytics_demo", "twitter_demo", "yelp_demo"]'>
-                      <i class="fa fa-download"></i> ${ apps['search'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'spark' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('notebook:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['spark'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'oozie' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('oozie:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['oozie'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'hbase' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('hbase:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['hbase'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'pig' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('pig:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['pig'].nice_name }
-                    </a>
-                  </li>
-                % endif
-                % if 'oozie' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('oozie:install_examples') }">
-                      <i class="fa fa-download"></i> ${ _('Job Editor') }
-                    </a>
-                  </li>
-                % elif 'jobsub' in app_names:
-                  <li>
-                    <a href="javascript:void(0)" class="installBtn" data-loading-text="${ _('Installing...') }"
-                       data-sample-url="${ url('oozie:install_examples') }">
-                      <i class="fa fa-download"></i> ${ apps['jobsub'].nice_name }
-                    </a>
-                  </li>
-                % endif
-              % endif
-              </ul>
-            </div>
-          </div>
-
-          <div id="step4" class="stepDetails hide">
-            <div>
-              <h3>${ _('Create or import users') }</h3>
-              <a href="${ url('useradmin:useradmin.views.list_users') }"
-                 % if not is_embeddable:
-                 target="_blank"
-                 % endif
-              ><i class="fa fa-user"></i> ${ _('User Admin') }</a>
-            </div>
-
-            <div class="margin-top-30">
-              <h3>${ _('Anonymous usage analytics') }</h3>
-              <label class="checkbox">
-                <input class="updatePreferences" type="checkbox" name="collect_usage" style="margin-right: 10px"
-                  title="${ _('Check to enable usage analytics') }" ${ collect_usage and 'checked' or '' }/>
-                ${ _('Help improve Hue with anonymous usage analytics.') }
-                <a href="javascript:void(0)" style="display: inline" data-trigger="hover" data-toggle="popover"
-                  data-placement="right" rel="popover"
-                  title="${ _('How does it work?') }"
-                  data-content="${ _('Hue is using Google Analytics to see how many times an application or specific section of an application is used, nothing more.') }">
-                   <i class="fa fa-question-circle"></i>
-                </a>
-              </label>
-            </div>
-
-            % if not is_embeddable:
-            <div class="margin-top-30">
-              <h3>${ _('Skip wizard next time') }</h3>
-              <label class="checkbox">
-                <input id="updateSkipWizard" type="checkbox" style="margin-right: 10px" title="${ _('Check to skip this wizard next time.') }"/>
-                ${ _('Skip the Quick Start Wizard at next login and land directly on your starred application.') }
-              </label>
-            </div>
-            % endif
-
-          </div>
-          </div>
-
-        </div>
-      </div>
-      <div class="card-body">
-        <div class="form-actions">
-          <a id="backBtn" class="btn disabled">${ _('Back') }</a>
-          <a id="nextBtn" class="btn btn-primary disable-feedback">${ _('Next') }</a>
-          <a id="doneBtn" class="btn btn-primary disable-feedback hide">${ _('Done') }</a>
-          <span class="pull-right muted" style="padding-right:30px">${ _('Hue and the Hue logo are trademarks of Cloudera, Inc.') }</span>
-        </div>
-      </div>
-      % else:
-       <div class="card-body">
-        <p>
-          ${ _('Learn more about Hue and SQL Querying on') } <a href="https://gethue.com" target="_blank">https://gethue.com</a>.
-          <br/>
-          <br/>
-          <span class="pull-right muted">${ _('Hue and the Hue logo are trademarks of Cloudera, Inc.') }</span>
-          % if not user.is_authenticated:
-            <br/>
-            <a href="${ url('desktop_views_home2') }" class="btn btn-primary" style="margin-top: 50px;margin-bottom: 20px">
-              <i class="fa fa-sign-in"></i> ${ _('Sign in now!') }
-            </a>
-          % endif
-        </p>
-       </div>
-      % endif
-
-    </div>
-  </div>
-
+<div id="Overview">
+  <OverviewTab class='antd cuix' data-reactcomponent='Overview'></OverviewTab>
 </div>
 
-% if is_admin(user):
-<style type="text/css">
-  .steps {
-    min-height: 300px;
-  }
-
-  input[type=submit] {
-    margin-left: 50px;
-  }
-
-  ul.samples li {
-    padding-bottom: 5px;
-  }
-
-  .nav-pills.nav-vertical-pills li {
-    float: none;
-    margin-bottom: 10px;
-  }
-
-  .nav-pills.nav-vertical-pills li a {
-    line-height: 20px;
-  }
-
-</style>
-
-<script src="${ static('desktop/js/hue.routie.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/admin-wizard-inline.js') }" type="text/javascript"></script>
-% endif
-
-% if not is_embeddable:
-  ${ commonfooter(request, messages) | n,unicode }
-% endif

+ 0 - 44
apps/hive/src/hive/tests.py

@@ -21,47 +21,3 @@ import pytest
 
 import aws
 from desktop.lib.django_test_util import make_logged_in_client
-
-
-@pytest.mark.django_db
-def test_config_check():
-  with patch('beeswax.hive_site.get_metastore_warehouse_dir') as get_metastore_warehouse_dir:
-    with patch('aws.s3.s3fs.S3FileSystem._stats') as s3_stat:
-      with patch('aws.conf.is_enabled') as is_s3_enabled:
-        reset = aws.conf.AWS_ACCOUNTS.set_for_testing({
-            'default': {
-                'region': 'us-east-1',
-                'access_key_id': 'access_key_id',
-                'secret_access_key': 'secret_access_key'
-            }
-        }),
-        warehouse = 's3a://yingsdx0602/data1/warehouse/tablespace/managed/hive'
-        get_metastore_warehouse_dir.return_value = warehouse
-        is_s3_enabled.return_value = True
-        s3_stat.return_value = Mock(
-            DIR_MODE=16895,
-            FILE_MODE=33206,
-            aclBit=False,
-            atime=None,
-            group='',
-            isDir=True,
-            mode=16895,
-            mtime=None,
-            name='hive',
-            path='s3a://yingchensdx/data1/warehouse/tablespace/managed/hive/',
-            size=0,
-            type='DIRECTORY',
-            user=''
-        )
-
-        try:
-          cli = make_logged_in_client()
-          resp = cli.get('/desktop/debug/check_config')
-          s3_stat.assert_called()
-          err_msg = 'Failed to access Hive warehouse: %s' % warehouse
-          if not isinstance(err_msg, bytes):
-            err_msg = err_msg.encode('utf-8')
-          assert err_msg not in resp.content, resp
-        finally:
-          for old_conf in reset:
-            old_conf()

+ 1 - 1
desktop/core/src/desktop/api2_tests.py

@@ -931,7 +931,7 @@ class TestCheckConfigAPI:
   def test_check_config_success(self):
     with patch('desktop.api2.os.path.realpath') as mock_hue_conf_dir:
       with patch('desktop.api2._get_config_errors') as mock_get_config_errors:
-        request = Mock(method='POST')
+        request = Mock(method='GET')
         mock_hue_conf_dir.return_value = '/test/hue/conf'
         mock_get_config_errors.return_value = [
           {"name": "Hive", "message": "The application won't work without a running HiveServer2."},

+ 1 - 1
desktop/core/src/desktop/api_public.py

@@ -72,7 +72,7 @@ def download_hue_logs(request):
   return logs_api.download_hue_logs(django_request)
 
 
-@api_view(["POST"])
+@api_view(["GET"])
 def check_config(request):
   django_request = get_django_request(request)
   return desktop_api.check_config(django_request)

+ 5 - 0
desktop/core/src/desktop/js/apps/admin/Components/utils.tsx → desktop/core/src/desktop/js/apps/admin/Components/utils.ts

@@ -15,3 +15,8 @@
 // limitations under the License.
 
 export const SERVER_LOGS_API_URL = '/api/v1/logs';
+export const CHECK_CONFIG_EXAMPLES_API_URL = '/api/v1/check_config';
+export const ANALYTICS_PREFERENCES_API_URL = '/about/update_preferences';
+export const INSTALL_APP_EXAMPLES_API_URL = '/api/v1/install_app_examples';
+export const INSTALL_AVAILABLE_EXAMPLES_API_URL = '/api/v1/available_app_examples';
+export const HUE_DOCS_CONFIG_URL = 'https://docs.gethue.com/administrator/configuration/';

+ 4 - 3
desktop/core/src/desktop/js/apps/admin/Configuration/ConfigurationTab.tsx

@@ -15,7 +15,8 @@
 // limitations under the License.
 
 import React, { useState, useEffect, useMemo } from 'react';
-import { Spin, Alert } from 'antd';
+import Loading from 'cuix/dist/components/Loading';
+import Alert from 'cuix/dist/components/Alert';
 import { i18nReact } from '../../../utils/i18nReact';
 import AdminHeader from '../AdminHeader';
 import { ConfigurationValue } from './ConfigurationValue';
@@ -150,7 +151,7 @@ const Configuration: React.FC = (): JSX.Element => {
 
   return (
     <div className="config-component">
-      <Spin spinning={loading}>
+      <Loading spinning={loading}>
         {error && (
           <Alert
             message={`Error: ${error}`}
@@ -182,7 +183,7 @@ const Configuration: React.FC = (): JSX.Element => {
               ))}
           </>
         )}
-      </Spin>
+      </Loading>
     </div>
   );
 };

+ 4 - 3
desktop/core/src/desktop/js/apps/admin/Metrics/MetricsTab.tsx

@@ -16,7 +16,8 @@
 
 import React, { useState, useEffect } from 'react';
 import MetricsTable, { MetricsResponse, MetricsTableProps } from './MetricsTable';
-import { Spin, Alert } from 'antd';
+import Loading from 'cuix/dist/components/Loading';
+import Alert from 'cuix/dist/components/Alert';
 import { get } from '../../../api/utils';
 import { i18nReact } from '../../../utils/i18nReact';
 import AdminHeader from '../AdminHeader';
@@ -94,7 +95,7 @@ const Metrics: React.FC = (): JSX.Element => {
 
   return (
     <div className="cuix antd metrics-component">
-      <Spin spinning={loading}>
+      <Loading spinning={loading}>
         {!error && (
           <AdminHeader
             options={['All', ...filteredKeys]}
@@ -124,7 +125,7 @@ const Metrics: React.FC = (): JSX.Element => {
               </div>
             ))}
         </div>
-      </Spin>
+      </Loading>
     </div>
   );
 };

+ 1 - 1
desktop/core/src/desktop/js/apps/admin/Metrics/MetricsTable.tsx

@@ -114,7 +114,7 @@ const MetricsTable: React.FC<MetricsTableProps> = ({ caption, dataSource }) => {
     () =>
       dataSource.map(item => ({
         ...item,
-        name: t(metricLabels[item.name]) || item.name
+        name: metricLabels[item.name] || item.name
       })),
     [dataSource]
   );

+ 77 - 0
desktop/core/src/desktop/js/apps/admin/Overview/Analytics.tsx

@@ -0,0 +1,77 @@
+// 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 React, { useState } from 'react';
+import huePubSub from '../../../utils/huePubSub';
+import { i18nReact } from '../../../utils/i18nReact';
+import Input from 'cuix/dist/components/Input';
+import { post } from '../../../api/utils';
+import { ANALYTICS_PREFERENCES_API_URL } from '../Components/utils';
+import './Overview.scss';
+
+interface UpdatePreferences {
+  status: number;
+  message?: string;
+}
+
+const Analytics = (): JSX.Element => {
+  const [collectUsage, setCollectUsage] = useState<boolean>(false);
+  const { t } = i18nReact.useTranslation();
+
+  const saveCollectUsagePreference = async (collectUsage: boolean) => {
+    const response = await post<UpdatePreferences>(ANALYTICS_PREFERENCES_API_URL, {
+      collect_usage: collectUsage
+    });
+
+    if (response.status === 0) {
+      const successMessage = collectUsage
+        ? t('Analytics have been activated.')
+        : t('Analytics have been deactivated.');
+      huePubSub.publish('hue.global.info', { message: successMessage });
+    } else {
+      const errorMessage = collectUsage
+        ? t('Failed to activate analytics.')
+        : t('Failed to deactivate analytics.');
+      huePubSub.publish('hue.global.error', { message: errorMessage });
+    }
+  };
+
+  const handleCheckboxChange = event => {
+    const newPreference = event.target.checked;
+    setCollectUsage(newPreference);
+    saveCollectUsagePreference(newPreference);
+  };
+
+  return (
+    <div className="overview-analytics">
+      <h3>{t('Anonymous usage analytics')}</h3>
+      <div className="analytics-checkbox-container">
+        <Input
+          type="checkbox"
+          className="analytics__checkbox-icon"
+          id="usage_analytics"
+          checked={collectUsage}
+          onChange={handleCheckboxChange}
+        />
+        <label htmlFor="usage_analytics" className="usage__analytics">
+          {t('Help improve Hue with anonymous usage analytics.')}
+        </label>
+      </div>
+    </div>
+  );
+};
+
+export default Analytics;

+ 118 - 0
desktop/core/src/desktop/js/apps/admin/Overview/ConfigStatus.tsx

@@ -0,0 +1,118 @@
+// 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 React from 'react';
+import Loading from 'cuix/dist/components/Loading';
+import Alert from 'cuix/dist/components/Alert';
+import Table from 'cuix/dist/components/Table';
+import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
+import { CHECK_CONFIG_EXAMPLES_API_URL } from '../Components/utils';
+import { HUE_DOCS_CONFIG_URL } from '../Components/utils';
+import { i18nReact } from '../../../utils/i18nReact';
+import './Overview.scss';
+
+interface ConfigError {
+  name: string;
+  message: string;
+}
+interface CheckConfigResponse {
+  hueConfigDir: string;
+  configErrors: ConfigError[];
+}
+
+const ConfigStatus = (): JSX.Element => {
+  const { t } = i18nReact.useTranslation();
+  const { data, loading, error } = useLoadData<CheckConfigResponse>(CHECK_CONFIG_EXAMPLES_API_URL);
+
+  const columns = [
+    {
+      dataIndex: 'name',
+      render: name => <span className="config__table-name">{name}</span>
+    },
+    {
+      key: 'details',
+      render: record => (
+        <div>
+          {record.value && (
+            <p>
+              {t('Current value')}: <span className="config__table-value">{record.value}</span>
+            </p>
+          )}
+          <p>{record.message}</p>
+        </div>
+      )
+    }
+  ];
+
+  const configErrorsExist = Boolean(data?.configErrors?.length);
+
+  return (
+    <div className="overview-config">
+      {loading && <Loading spinning={loading} className="config__spin" />}
+      {error && (
+        <Alert
+          message={`${t('Error:')} ${error}`}
+          description={t('An error occurred while attempting to load the configuration status.')}
+          type="error"
+        />
+      )}
+      {!loading && !error && (
+        <>
+          <h1>{t('Checking current configuration')}</h1>
+          {data?.hueConfigDir && (
+            <div>
+              {t('Configuration files located in: ')}
+              <span className="config__address-value">{data['hueConfigDir']}</span>
+            </div>
+          )}
+
+          {configErrorsExist && data ? (
+            <>
+              <Alert
+                message={
+                  <span>
+                    <a href={HUE_DOCS_CONFIG_URL} target="_blank" className="config__link">
+                      {t('Potential misconfiguration detected.')}
+                    </a>{' '}
+                    {t('Fix and restart Hue.')}
+                  </span>
+                }
+                type="warning"
+                className="config__alert-margin"
+              />
+
+              <Table
+                dataSource={data.configErrors}
+                columns={columns}
+                rowKey={record => `${record.name}-${record.message.slice(1, 50)}`}
+                pagination={false}
+                showHeader={false}
+              />
+            </>
+          ) : (
+            <Alert
+              message={t('All OK. Configuration check passed.')}
+              type="success"
+              className="config__alert-margin"
+            />
+          )}
+        </>
+      )}
+    </div>
+  );
+};
+
+export default ConfigStatus;

+ 139 - 0
desktop/core/src/desktop/js/apps/admin/Overview/Examples.tsx

@@ -0,0 +1,139 @@
+// 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 React, { useState, useEffect } from 'react';
+import LinkButton from 'cuix/dist/components/Button/LinkButton';
+import { DownloadOutlined } from '@ant-design/icons';
+import Loading from 'cuix/dist/components/Loading';
+import {
+  INSTALL_APP_EXAMPLES_API_URL,
+  INSTALL_AVAILABLE_EXAMPLES_API_URL
+} from '../Components/utils';
+import { get, post } from '../../../api/utils';
+import huePubSub from '../../../utils/huePubSub';
+import { i18nReact } from '../../../utils/i18nReact';
+import './Overview.scss';
+
+const exampleAppsWithData = [
+  { id: 'search', name: 'Solr Search', data: ['log_analytics_demo', 'twitter_demo', 'yelp_demo'] }
+];
+
+const excludedApps = ['notebook'];
+
+type InstallExamplesResponse = {
+  status: number;
+  message?: string;
+};
+
+const Examples = (): JSX.Element => {
+  const { t } = i18nReact.useTranslation();
+  const [installingAppId, setInstallingAppId] = useState<string>('');
+  const [availableApps, setAvailableApps] = useState<{ [key: string]: string }>({});
+  const [loading, setLoading] = useState<boolean>(true);
+
+  useEffect(() => {
+    const fetchAvailableApps = async () => {
+      try {
+        const response = await get(INSTALL_AVAILABLE_EXAMPLES_API_URL, {});
+        if (response.apps) {
+          const filteredApps = Object.entries(response.apps)
+            .filter(([appId]) => !excludedApps.includes(appId))
+            .reduce((apps, [appId, appName]) => ({ ...apps, [appId]: appName }), {});
+
+          setAvailableApps(filteredApps);
+        }
+      } catch (error) {
+        console.error('Error fetching available app examples:', error);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchAvailableApps();
+  }, []);
+
+  const installExamplesCall = async (url: string, data: Record<string, unknown>) => {
+    const response = await post<InstallExamplesResponse>(url, data);
+    return response;
+  };
+
+  const handleInstall = async (exampleApp: { id: string; name: string }) => {
+    setInstallingAppId(exampleApp.id);
+    const url = INSTALL_APP_EXAMPLES_API_URL;
+
+    let actualAppName;
+    switch (exampleApp.id) {
+      case 'spark':
+        actualAppName = 'notebook';
+        break;
+      case 'jobsub':
+        actualAppName = 'oozie';
+        break;
+      default:
+        actualAppName = exampleApp.id;
+    }
+
+    try {
+      const appWithExtraData = exampleAppsWithData.find(app => app.id === exampleApp.id);
+      if (appWithExtraData && appWithExtraData.data) {
+        const installPromises = appWithExtraData.data.map(eachData =>
+          installExamplesCall(url, {
+            app_name: actualAppName,
+            data: eachData
+          })
+        );
+        await Promise.all(installPromises);
+      } else {
+        await installExamplesCall(url, { app_name: actualAppName });
+      }
+      const message = `${actualAppName} ${t('examples installed successfully')}`;
+      huePubSub.publish('hue.global.info', { message });
+    } catch (error) {
+      const errorMessage = error.message
+        ? `${t('An error occurred while installing')} ${actualAppName}: ${error.message}`
+        : `${t('An error occurred while installing')} ${actualAppName}.`;
+      huePubSub.publish('hue.global.error', { message: errorMessage });
+    } finally {
+      setInstallingAppId('');
+    }
+  };
+
+  return (
+    <div className="overview-examples">
+      <h3>{t('Install some data examples')}</h3>
+      {loading ? (
+        <Loading spinning={loading} />
+      ) : (
+        Object.entries(availableApps).map(([appId, appName]) => (
+          <div key={appId}>
+            <LinkButton
+              onClick={() => handleInstall({ id: appId, name: appName })}
+              disabled={installingAppId === appId}
+              icon={<DownloadOutlined />}
+              className="examples__install-btn"
+            >
+              {installingAppId === appId
+                ? t('Installing...')
+                : appName[0].toUpperCase() + appName.slice(1)}
+            </LinkButton>
+          </div>
+        ))
+      )}
+    </div>
+  );
+};
+
+export default Examples;

+ 87 - 0
desktop/core/src/desktop/js/apps/admin/Overview/Overview.scss

@@ -0,0 +1,87 @@
+// 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 '../../../components/styles/variables';
+
+.antd.cuix {
+  .hue-overview-component {
+    background-color: $fluidx-gray-100;
+    padding: 24px;
+
+    .config__spin {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      height: 100vh;
+    }
+
+    .config__address-value {
+      color: $fluidx-blue-600;
+      padding: 2px 4px;
+      background-color: $fluidx-gray-040;
+      border: 1px solid $fluidx-gray-400;
+      border-radius: 2px;
+    }
+
+    .config__link {
+      color: $fluidx-blue-600;
+      cursor: pointer;
+    }
+
+    .config__alert-margin {
+      margin: 10px 0;
+    }
+
+    .config__table-name, .config__table-value {
+      color: $fluidx-gray-900;
+      font-size: 12px;
+      border-radius: 5px;
+      margin-left: 8px;
+      padding: 2px 4px;
+      background-color: $fluidx-gray-040;
+      border: 1px solid $fluidx-gray-400;
+    }
+
+    .overview-examples,
+    .overview-analytics {
+      height: 100vh;
+    }
+
+    .examples__install-btn{
+      margin: 10px;
+    }
+
+    .analytics-checkbox-container {
+      display: flex;
+      align-items: center;
+    }
+
+    .analytics__checkbox-icon {
+      width: auto;
+      height: auto;
+      min-height: 0;
+    }
+
+    .usage__analytics {
+      margin-left: 8px;
+    }
+
+    .overview__trademark-text {
+      text-align: right;
+      padding: 10px;
+    }
+  }
+}

+ 145 - 0
desktop/core/src/desktop/js/apps/admin/Overview/OverviewTab.test.tsx

@@ -0,0 +1,145 @@
+// 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 '@testing-library/jest-dom';
+import React from 'react';
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import Overview from './OverviewTab';
+import * as hueConfigModule from '../../../config/hueConfig';
+import Examples from './Examples';
+import Analytics from './Analytics';
+import {
+  INSTALL_APP_EXAMPLES_API_URL,
+  INSTALL_AVAILABLE_EXAMPLES_API_URL
+} from '../Components/utils';
+import { get, post } from '../../../api/utils';
+
+jest.mock('../../../api/utils', () => ({
+  post: jest.fn(),
+  get: jest.fn()
+}));
+
+jest.mock('./ConfigStatus', () => () => <div>MockedConfigStatusComponent</div>);
+
+jest.mock('../../../config/hueConfig', () => ({
+  getLastKnownConfig: jest.fn()
+}));
+
+describe('OverviewTab', () => {
+  beforeEach(() => {
+    (hueConfigModule.getLastKnownConfig as jest.Mock).mockReturnValue({
+      hue_config: { is_admin: true }
+    });
+  });
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
+
+  test('renders the Tabs with the correct tab labels', () => {
+    render(<Overview />);
+    expect(screen.getByText('Config Status')).toBeInTheDocument();
+    expect(screen.getByText('Examples')).toBeInTheDocument();
+    expect(screen.getByText('Analytics')).toBeInTheDocument();
+  });
+
+  describe('Analytics Component', () => {
+    test('renders Analytics tab and can interact with the checkbox', async () => {
+      (post as jest.Mock).mockResolvedValue({ status: 0, message: 'Success' });
+      render(<Analytics />);
+      const checkbox = screen.getByLabelText(/Help improve Hue with anonymous usage analytics./i);
+
+      expect(checkbox).not.toBeChecked();
+      await userEvent.click(checkbox);
+      expect(checkbox).toBeChecked();
+      expect(post).toHaveBeenCalledWith('/about/update_preferences', {
+        collect_usage: true
+      });
+      userEvent.click(checkbox);
+      await waitFor(() => expect(checkbox).not.toBeChecked());
+      expect(post).toHaveBeenCalledWith('/about/update_preferences', {
+        collect_usage: false
+      });
+    });
+  });
+
+  describe('Examples component', () => {
+    const availableAppsResponse = {
+      apps: {
+        hive: 'Hive',
+        impala: 'Impala',
+        search: 'Solr Search'
+      }
+    };
+    beforeEach(() => {
+      (get as jest.Mock).mockImplementation(url => {
+        if (url === INSTALL_AVAILABLE_EXAMPLES_API_URL) {
+          return Promise.resolve(availableAppsResponse);
+        }
+        return Promise.reject();
+      });
+
+      (post as jest.Mock).mockImplementation(() =>
+        Promise.resolve({ status: 0, message: 'Success' })
+      );
+    });
+
+    afterEach(() => {
+      jest.clearAllMocks();
+    });
+
+    test('fetch and display available apps', async () => {
+      render(<Examples />);
+
+      await waitFor(() => {
+        expect(get).toHaveBeenCalledWith(INSTALL_AVAILABLE_EXAMPLES_API_URL, {});
+        Object.entries(availableAppsResponse.apps).forEach(([, appName]) => {
+          expect(screen.getByText(appName)).toBeInTheDocument();
+        });
+      });
+    });
+
+    test('post call to install apps without data like hive when the install button is clicked', async () => {
+      render(<Examples />);
+
+      await waitFor(() => {
+        const installButton = screen.getByText('Hive');
+        userEvent.click(installButton);
+        expect(post).toHaveBeenCalledWith(INSTALL_APP_EXAMPLES_API_URL, { app_name: 'hive' });
+      });
+    });
+
+    test('post call to install Solr Search example and its data when the install button is clicked', async () => {
+      render(<Examples />);
+
+      const solrData = ['log_analytics_demo', 'twitter_demo', 'yelp_demo'];
+      await waitFor(() => screen.getByText('Solr Search'));
+      const installButton = screen.getByText('Solr Search');
+      userEvent.click(installButton);
+
+      await waitFor(() => {
+        solrData.forEach(dataEntry => {
+          expect(post).toHaveBeenCalledWith(INSTALL_APP_EXAMPLES_API_URL, {
+            app_name: 'search',
+            data: dataEntry
+          });
+        });
+      });
+
+      expect(post).toHaveBeenCalledTimes(solrData.length);
+    });
+  });
+});

+ 56 - 0
desktop/core/src/desktop/js/apps/admin/Overview/OverviewTab.tsx

@@ -0,0 +1,56 @@
+// 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 React from 'react';
+import { Tabs } from 'antd';
+import Examples from './Examples';
+import ConfigStatus from './ConfigStatus';
+import Analytics from './Analytics';
+import { i18nReact } from '../../../utils/i18nReact';
+import './Overview.scss';
+
+const Overview = (): JSX.Element => {
+  const { t } = i18nReact.useTranslation();
+
+  const items = [
+    {
+      label: t('Config Status'),
+      key: '1',
+      children: <ConfigStatus />
+    },
+    {
+      label: t('Examples'),
+      key: '2',
+      children: <Examples />
+    },
+    {
+      label: t('Analytics'),
+      key: '3',
+      children: <Analytics />
+    }
+  ];
+
+  return (
+    <div className="hue-overview-component">
+      <Tabs tabPosition="left" items={items} />
+      <div className="overview__trademark-text">
+        {t('Hue and the Hue logo are trademarks of Cloudera, Inc.')}
+      </div>
+    </div>
+  );
+};
+
+export default Overview;

+ 3 - 0
desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsHeader.scss

@@ -58,6 +58,9 @@
 
       .server__checkbox-icon {
         margin-right: 2px;
+        width: auto;
+        height: auto;
+        min-height: 0;
       }
 
       .server__download-button {

+ 4 - 3
desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsHeader.tsx

@@ -15,7 +15,7 @@
 // limitations under the License.
 
 import React, { useState } from 'react';
-import { Input, Checkbox } from 'antd';
+import Input from 'cuix/dist/components/Input';
 import Button from 'cuix/dist/components/Button';
 import Search from '@cloudera/cuix-core/icons/react/SearchIcon';
 import Download from '@cloudera/cuix-core/icons/react/DownloadIcon';
@@ -62,8 +62,9 @@ const ServerLogsHeader: React.FC<ServerLogsHeaderProps> = ({
       />
 
       <div className="server--right-actions">
-        <span className="server__host-text">{t(`Host: ${hostName}`)}</span>
-        <Checkbox
+        <span className="server__host-text">{`${t('Host:')} ${hostName}`}</span>
+        <Input
+          type="checkbox"
           onChange={e => {
             setWrapLogs(e.target.checked);
             onWrapLogsChange(e.target.checked);

+ 2 - 2
desktop/core/src/desktop/js/apps/admin/ServerLogs/ServerLogsTab.tsx

@@ -15,7 +15,7 @@
 // limitations under the License.
 
 import React, { useState } from 'react';
-import { Alert } from 'antd';
+import Alert from 'cuix/dist/components/Alert';
 import ServerLogsHeader from './ServerLogsHeader';
 import { i18nReact } from '../../../utils/i18nReact';
 import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
@@ -43,7 +43,7 @@ const ServerLogs: React.FC = (): JSX.Element => {
     return (
       <div className="hue-server-logs-component">
         <Alert
-          message={t(`Error: ${error}`)}
+          message={`${t('Error:')} ${error}`}
           description={t('An error occurred while fetching server logs.')}
           type="error"
         />

+ 3 - 0
desktop/core/src/desktop/js/reactComponents/imports.js

@@ -10,6 +10,9 @@ export async function loadComponent(name) {
     case 'StorageBrowserPage':
       return (await import('../apps/storageBrowser/StorageBrowserPage')).default;
 
+    case 'Overview':
+      return (await import('../apps/admin/Overview/OverviewTab')).default;
+
     case 'Metrics':
       return (await import('../apps/admin/Metrics/MetricsTab')).default;
 

+ 3 - 179
desktop/core/src/desktop/static/desktop/js/admin-wizard-inline.js

@@ -1,179 +1,3 @@
-routie.setPathname('/about');
-var AdminWizardViewModel = function () {
-  var self = this;
-
-  self.connectors = ko.observableArray();
-  self.isInstallingSample = ko.observable(false);
-
-  self.installConnectorDataExample = function (connector, event) {
-    self.isInstallingSample(true);
-    $.post("/notebook/install_examples", {
-      connector: connector.id
-    }, function (data) {
-      if (data.message) {
-        huePubSub.publish('hue.global.info', { message: data.message });
-      }
-      if (data.errorMessage) {
-        huePubSub.publish('hue.global.error', { message: data.errorMessage });
-      }
-      if (data.status == 0 && $(event.target).data("is-connector")) {
-        huePubSub.publish('cluster.config.refresh.config');
-      }
-    }).always(function (data) {
-      self.isInstallingSample(false);
-    });
-  }
-};
-
-function installConnectorExample() {
-  var button = $(this);
-  $(button).button('loading');
-  $.post(button.data("sample-url"), function (data) {
-    if (data.status == 0) {
-      if (data.message) {
-        huePubSub.publish('hue.global.info', { message: data.message });
-      } else {
-        huePubSub.publish('hue.global.info', { message: 'Examples refreshed' });
-      }
-      if ($(button).data("is-connector")) {
-        huePubSub.publish('cluster.config.refresh.config');
-      }
-    } else {
-      huePubSub.publish('hue.global.error', { message: data.message });
-    }
-  })
-    .always(function (data) {
-      $(button).button('reset');
-    });
-}
-
-$(document).ready(function () {
-
-  var adminWizardViewModel = new AdminWizardViewModel();
-  ko.applyBindings(adminWizardViewModel, $('#adminWizardComponents')[0]);
-
-  function checkConfig() {
-    $.get("/desktop/debug/check_config", function (response) {
-      $("#check-config-section .spinner").css({
-        'position': 'absolute',
-        'top': '-100px'
-      });
-      $("#check-config-section .info").html(response);
-      $("#check-config-section .info").removeClass('hide');
-    })
-      .fail(function () {
-        huePubSub.publish('hue.global.error', { message: 'Check config failed: ' });
-      });
-  }
-
-  $("[rel='popover']").popover();
-
-
-  $(".installBtn").click(installConnectorExample);
-
-  $(".installAllBtn").click(function () {
-    var button = $(this);
-    $(button).button('loading');
-    var calls = jQuery.map($(button).data("sample-data"), function (app) {
-      return $.post($(button).data("sample-url"), { data: app }, function (data) {
-        if (data.status != 0) {
-          huePubSub.publish('hue.global.error', { message: data.message });
-        }
-      });
-    });
-    $.when.apply(this, calls)
-      .then(function () {
-        huePubSub.publish('hue.global.info', { message: 'Examples refreshed' });
-      })
-      .always(function (data) {
-        $(button).button('reset');
-      });
-  });
-
-  var currentStep = "step1";
-
-  routie({
-    "step1": function () {
-      showStep("step1");
-    },
-    "step2": function () {
-      showStep("step2");
-    },
-    "step3": function () {
-      showStep("step3");
-    },
-    "step4": function () {
-      showStep("step4");
-    }
-  });
-
-  if (window.location.hash === '') {
-    checkConfig();
-  }
-
-  function showStep(step) {
-    if (window.location.hash === '#step1') {
-      checkConfig();
-    }
-
-    currentStep = step;
-    if (step != "step1") {
-      $("#backBtn").removeClass("disabled");
-    } else {
-      $("#backBtn").addClass("disabled");
-    }
-
-    if (step != $(".stepDetails:last").attr("id")) {
-      $("#nextBtn").removeClass("hide");
-      $("#doneBtn").addClass("hide");
-    } else {
-      $("#nextBtn").addClass("hide");
-      $("#doneBtn").removeClass("hide");
-    }
-
-    $("a.step").parent().removeClass("active");
-    $("a.step[href='#" + step + "']").parent().addClass("active");
-    if (step == "step4") {
-      $("#lastStep").parent().addClass("active");
-    }
-    $(".stepDetails").hide();
-    $("#" + step).show();
-  }
-
-  $("#backBtn").click(function () {
-    var nextStep = (currentStep.substr(4) * 1 - 1);
-    if (nextStep >= 1) {
-      routie("step" + nextStep);
-    }
-  });
-
-  $("#nextBtn").click(function () {
-    var nextStep = (currentStep.substr(4) * 1 + 1);
-    if (nextStep <= $(".step").length) {
-      routie("step" + nextStep);
-    }
-  });
-
-  $("#doneBtn").click(function () {
-    huePubSub.publish('open.link', "/");
-  });
-
-  $(".updatePreferences").click(function () {
-    $.post("/about/update_preferences", $("input").serialize(), function (data) {
-      if (data.status == 0) {
-        huePubSub.publish('hue.global.info', { message: 'Configuration updated' });
-      } else {
-        huePubSub.publish('hue.global.error', { message: data.data });
-      }
-    });
-  });
-
-  $("#updateSkipWizard").prop('checked', $.cookie("hueLandingPage", { path: "/" }) == "home");
-
-  $("#updateSkipWizard").change(function () {
-    $.cookie("hueLandingPage", this.checked ? "home" : "wizard", {
-      path: "/",
-      secure: window.location.protocol.indexOf('https') > -1
-    });
-  });
-});
+(function () {
+  window.createReactComponents('#Overview');
+})();

+ 0 - 65
desktop/core/src/desktop/templates/check_config.mako

@@ -1,65 +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.
-
-<%!
-import sys
-
-from desktop.conf import has_connectors
-from desktop.auth.backend import is_hue_admin
-
-if sys.version_info[0] > 2:
-  from django.utils.translation import gettext as _
-else:
-  from django.utils.translation import ugettext as _
-%>
-
-% if is_hue_admin(user):
-  ${ _('Configuration files located in') } <code style="color: #0B7FAD">${ conf_dir }</code>
-% endif
-
-<br/><br/>
-
-% if error_list:
-  <div class="alert alert-warn">
-    <a href="https://docs.gethue.com/administrator/configuration/" target="_blank">
-    ${ _('Potential misconfiguration detected.') }
-    </a>
-    % if not has_connectors():
-      ${ _('Fix and restart Hue.') }
-    % endif
-  </div>
-  <br/>
-  <table class="table table-condensed">
-  % for error in error_list:
-    <tr>
-      <td width="15%">
-        <code>
-          ${ error['name'] | n }
-        </code>
-      </td>
-      <td>
-        ## Doesn't make sense to print the value of a BoundContainer
-        % if 'value' in error:
-          ${ _('Current value:') } <code>${ error['value'] }</code><br/>
-        % endif
-        ${ error['message'] | n }
-      </td>
-    </tr>
-  % endfor
-  </table>
-% else:
-  <h5>${ _('All OK. Configuration check passed.') }</h5>
-% endif

+ 0 - 5
desktop/core/src/desktop/templates/logs.mako

@@ -13,11 +13,6 @@
 ## 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 re
-import sys
-from desktop.views import commonheader, commonfooter
-%>
 
 <%namespace name="layout" file="about_layout.mako" />
 

+ 1 - 13
desktop/core/src/desktop/templates/metrics.mako

@@ -13,18 +13,9 @@
 ## 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 sys
-from desktop.views import commonheader, commonfooter
-from desktop import conf
-%>
 
 <%namespace name="layout" file="about_layout.mako" />
 
-%if not is_embeddable:
-${ commonheader(_('Metrics'), "about", user, request) | n,unicode }
-%endif
-
 ${layout.menubar(section='metrics')}
 
 <script src="${ static('desktop/js/metrics-inline.js') }" type="text/javascript"></script>
@@ -32,7 +23,4 @@ ${layout.menubar(section='metrics')}
 <div id="Metrics">
 <Metrics data-reactcomponent='Metrics'></Metrics>
 </div>
-
-%if not is_embeddable:
-${ commonfooter(request, messages) | n,unicode }
-%endif
+