This is an automated email from the ASF dual-hosted git repository.

jongyoul pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.12 by this push:
     new b05f247dd6 [ZEPPELIN-6085] Add configuration option for setting the 
default UI
b05f247dd6 is described below

commit b05f247dd6c017d2aa8fa0887a1073d6ec40d3c1
Author: ChanHo Lee <chanho0...@gmail.com>
AuthorDate: Wed Oct 9 15:50:16 2024 +0900

    [ZEPPELIN-6085] Add configuration option for setting the default UI
    
    ### What is this PR for?
    
    This PR introduces a new configuration option `zeppelin.default.ui` to set 
the default UI for Zeppelin.
    The available options for this setting are `new` and `classic`.
    By default, the value is set to `new`, meaning the new UI will be served at 
the root path (`"/"`), while the classic UI will be available at `"/classic"`.
    If the configuration is set to `classic`, the classic UI will be served at 
`"/"`, and the new UI at `"/new"`.
    
    ### What type of PR is it?
    
    Improvement
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * Open an issue on Jira https://issues.apache.org/jira/browse/ZEPPELIN/6085
    * Put link here, and add [ZEPPELIN-*Jira number*] in PR title, eg. 
[ZEPPELIN-533]
    
    ### How should this be tested?
    - Testing the `new` option :
      - Set the `zeppelin.default.ui` config to `new` (the default).
      - Verify that the new UI is served at the root (`"/"`) and the classic UI 
is available at `"/classic"`.
      - Verify that navigating between pages works without any issue.
      - Verify that the UI switching button works properly in both UIs.
    - Testing `classic` option :
      - Similar steps as the above, except the new UI is served at `"/classic"` 
and the classic UI is available at the root (`"/"`)
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? Yes, documentation for the new 
configuration option has been added.
    
    Closes #4824 from tbonelee/add-default-ui-config.
    
    Signed-off-by: Jongyoul Lee <jongy...@gmail.com>
    (cherry picked from commit 00b7c553694050d6d2ee4824a236bd76a7135646)
    Signed-off-by: Jongyoul Lee <jongy...@gmail.com>
---
 conf/zeppelin-site.xml.template                    |  6 +++++
 docs/quickstart/explore_ui.md                      | 15 +++++++++++
 docs/setup/operation/configuration.md              |  6 +++++
 .../zeppelin/conf/ZeppelinConfiguration.java       | 11 ++++++++
 .../apache/zeppelin/server/IndexHtmlServlet.java   | 29 +++++++++++++++++++++-
 .../org/apache/zeppelin/server/ZeppelinServer.java | 29 +++++++++++++++++-----
 .../zeppelin/server/IndexHtmlServletTest.java      |  4 +--
 zeppelin-web-angular/package.json                  |  2 +-
 .../src/app/share/header/header.component.html     |  2 +-
 .../src/app/share/header/header.component.ts       | 10 ++++++++
 zeppelin-web-angular/src/index.html                |  9 ++++++-
 .../src/components/navbar/navbar.controller.js     |  8 ++++++
 zeppelin-web/src/components/navbar/navbar.html     |  2 +-
 zeppelin-web/src/index.html                        |  9 ++++++-
 14 files changed, 128 insertions(+), 14 deletions(-)

diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template
index 9c719920ce..91b7a15029 100755
--- a/conf/zeppelin-site.xml.template
+++ b/conf/zeppelin-site.xml.template
@@ -49,6 +49,12 @@
   <description>Location of jetty temporary directory</description>
 </property>
 
+<property>
+  <name>zeppelin.default.ui</name>
+  <value>new</value>
+  <description>Default UI for Zeppelin. Options: classic or new</description>
+</property>
+
 <property>
   <name>zeppelin.notebook.dir</name>
   <value>notebook</value>
diff --git a/docs/quickstart/explore_ui.md b/docs/quickstart/explore_ui.md
index 73156f39e7..5a466385e8 100644
--- a/docs/quickstart/explore_ui.md
+++ b/docs/quickstart/explore_ui.md
@@ -35,6 +35,21 @@ Afterward, you can switch to the classic UI via the `Swtich 
to Classic UI` butto
 
 <img 
src="{{BASE_PATH}}/assets/themes/zeppelin/img/ui-img/switch_to_classic_ui.png" 
width="130" />
 
+
+### Configuring the default UI
+
+Zeppelin allows you to configure the default, especially for users who prefer 
the classic UI.
+
+To set the default UI to classic, add the following property to the 
`zeppelin-site.xml` file:
+
+```xml
+<property>
+  <name>zeppelin.default.ui</name>
+  <value>classic</value>
+  <description>Default UI for Zeppelin. Options: classic or new. Default 
configuration is 'new'</description>
+</property>
+```
+
 ## Main home
 
 The first time you connect to Zeppelin ([default installations start on 
http://localhost:8080](http://localhost:8080/)), you'll land at the main page 
similar to the below screen capture.
diff --git a/docs/setup/operation/configuration.md 
b/docs/setup/operation/configuration.md
index e0c769202d..a2184314d2 100644
--- a/docs/setup/operation/configuration.md
+++ b/docs/setup/operation/configuration.md
@@ -217,6 +217,12 @@ Sources descending by priority:
     <td>webapps</td>
     <td>Location of the jetty temporary directory</td>
   </tr>
+  <tr>
+    <td><h6 class="properties">ZEPPELIN_DEFAULT_UI</h6></td>
+    <td><h6 class="properties">zeppelin.default.ui</h6></td>
+    <td>new</td>
+    <td>Default UI for Zeppelin. <br />Options: <code>classic</code> or 
<code>new</code></td>
+  </tr>
   <tr>
     <td><h6 class="properties">ZEPPELIN_NOTEBOOK_DIR</h6></td>
     <td><h6 class="properties">zeppelin.notebook.dir</h6></td>
diff --git 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
index 5ac7587f29..b590fa8dda 100644
--- 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
+++ 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
@@ -79,6 +79,11 @@ public class ZeppelinConfiguration {
     DOCKER
   }
 
+  public enum DEFAULT_UI {
+    NEW,
+    CLASSIC
+  }
+
   // private constructor, so that it is singleton.
   private ZeppelinConfiguration(@Nullable String filename) {
      try {
@@ -882,6 +887,10 @@ public class ZeppelinConfiguration {
     return getBoolean(ConfVars.ZEPPELIN_METRIC_ENABLE_PROMETHEUS);
   }
 
+  public DEFAULT_UI getDefaultUi() {
+    return 
DEFAULT_UI.valueOf(getString(ConfVars.ZEPPELIN_DEFAULT_UI).toUpperCase());
+  }
+
   /**
    * This method return the complete configuration map
    * @return
@@ -942,6 +951,8 @@ public class ZeppelinConfiguration {
     ZEPPELIN_WAR("zeppelin.war", "zeppelin-web/dist"),
     ZEPPELIN_ANGULAR_WAR("zeppelin.angular.war", 
"zeppelin-web-angular/dist/zeppelin"),
     ZEPPELIN_WAR_TEMPDIR("zeppelin.war.tempdir", "webapps"),
+    // "new" or "classic"
+    ZEPPELIN_DEFAULT_UI("zeppelin.default.ui", "new"),
     ZEPPELIN_JMX_ENABLE("zeppelin.jmx.enable", false),
     ZEPPELIN_JMX_PORT("zeppelin.jmx.port", 9996),
 
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/IndexHtmlServlet.java
 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/IndexHtmlServlet.java
index bf32063a5d..b79149a2ba 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/IndexHtmlServlet.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/IndexHtmlServlet.java
@@ -46,10 +46,12 @@ public class IndexHtmlServlet extends HttpServlet {
 
   final String bodyAddon;
   final String headAddon;
+  final String baseHref;
 
-  public IndexHtmlServlet(ZeppelinConfiguration zConf) {
+  public IndexHtmlServlet(ZeppelinConfiguration zConf, String contextPath) {
     this.bodyAddon = zConf.getHtmlBodyAddon();
     this.headAddon = zConf.getHtmlHeadAddon();
+    this.baseHref = getBaseHref(contextPath);
   }
 
   @Override
@@ -79,6 +81,21 @@ public class IndexHtmlServlet extends HttpServlet {
             "Unable to process Head html addon. Could not find proper anchor 
in index.html.");
         }
       }
+      // process base href
+      if (baseHref != null) {
+        String baseTag = "<base href=\".*\">";
+        if (content.matches(baseTag)) {
+          content = content.replaceAll(baseTag, baseHref);
+        } else if (content.contains(TAG_HEAD_CLOSING)) {
+          content = content.replace(TAG_HEAD_CLOSING, baseHref + 
TAG_HEAD_CLOSING);
+        } else if (content.contains(TAG_BODY_OPENING)) {
+          content = content.replace(TAG_BODY_OPENING, baseHref + 
TAG_BODY_OPENING);
+        } else {
+          LOGGER.error(
+            "Unable to process base href. Could not find proper anchor in 
index.html.");
+        }
+      }
+
       resp.setContentType("text/html");
       resp.setStatus(HttpServletResponse.SC_OK);
       resp.getWriter().append(content);
@@ -86,4 +103,14 @@ public class IndexHtmlServlet extends HttpServlet {
       LOGGER.error("Error rendering index.html.", e);
     }
   }
+
+  private String getBaseHref(String contextPath) {
+    if (contextPath == null) {
+      return null;
+    }
+    if (!contextPath.endsWith("/")) {
+      contextPath = contextPath + "/";
+    }
+    return "<base href=\"" + contextPath + "\">";
+  }
 }
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index e41b9b6f94..3a5ef4bc31 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
@@ -62,6 +62,7 @@ import org.apache.shiro.web.env.EnvironmentLoaderListener;
 import org.apache.shiro.web.servlet.ShiroFilter;
 import org.apache.zeppelin.conf.ZeppelinConfiguration;
 import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
+import org.apache.zeppelin.conf.ZeppelinConfiguration.DEFAULT_UI;
 import org.apache.zeppelin.display.AngularObjectRegistryListener;
 import org.apache.zeppelin.healthcheck.HealthChecks;
 import org.apache.zeppelin.helium.ApplicationEventListener;
@@ -127,7 +128,8 @@ import org.slf4j.LoggerFactory;
 /** Main class of Zeppelin. */
 public class ZeppelinServer implements AutoCloseable {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(ZeppelinServer.class);
-  private static final String WEB_APP_CONTEXT_CLASSIC = "/classic";
+  private static final String NON_DEFAULT_NEW_UI_WEB_APP_CONTEXT_PATH = "/new";
+  private static final String NON_DEFAULT_CLASSIC_UI_WEB_APP_CONTEXT_PATH = 
"/classic";
   public static final String DEFAULT_SERVICE_LOCATOR_NAME = "shared-locator";
 
   private final AtomicBoolean duringShutdown = new AtomicBoolean(false);
@@ -221,11 +223,22 @@ public class ZeppelinServer implements AutoCloseable {
         });
 
     // Multiple Web UI
-    final WebAppContext defaultWebApp = setupWebAppContext(contexts, zConf, 
zConf.getString(ConfVars.ZEPPELIN_ANGULAR_WAR), zConf.getServerContextPath());
-    final WebAppContext classicWebApp = setupWebAppContext(contexts, zConf, 
zConf.getString(ConfVars.ZEPPELIN_WAR), WEB_APP_CONTEXT_CLASSIC);
+    String classicUiWebAppContextPath;
+    String newUiWebAppContextPath;
+    if (isNewUiDefault(zConf)) {
+      classicUiWebAppContextPath = NON_DEFAULT_CLASSIC_UI_WEB_APP_CONTEXT_PATH;
+      newUiWebAppContextPath = zConf.getServerContextPath();
+    } else {
+      classicUiWebAppContextPath = zConf.getServerContextPath();
+      newUiWebAppContextPath = NON_DEFAULT_NEW_UI_WEB_APP_CONTEXT_PATH;
+    }
+    final WebAppContext newUiWebApp = setupWebAppContext(contexts, zConf, 
zConf.getString(ConfVars.ZEPPELIN_ANGULAR_WAR),
+        newUiWebAppContextPath);
+    final WebAppContext classicUiWebApp = setupWebAppContext(contexts, zConf, 
zConf.getString(ConfVars.ZEPPELIN_WAR),
+        classicUiWebAppContextPath);
 
-    initWebApp(defaultWebApp);
-    initWebApp(classicWebApp);
+    initWebApp(newUiWebApp);
+    initWebApp(classicUiWebApp);
 
     NotebookRepo repo =
         ServiceLocatorUtilities.getService(sharedServiceLocator, 
NotebookRepo.class.getName());
@@ -592,7 +605,7 @@ public class ZeppelinServer implements AutoCloseable {
       webApp.setTempDirectory(warTempDirectory);
     }
     // Explicit bind to root
-    webApp.addServlet(new ServletHolder(new IndexHtmlServlet(zConf)), 
"/index.html");
+    webApp.addServlet(new ServletHolder(new IndexHtmlServlet(zConf, 
contextPath)), "/index.html");
     contexts.addHandler(webApp);
 
     webApp.addFilter(new FilterHolder(new CorsFilter(zConf)), "/*", 
EnumSet.allOf(DispatcherType.class));
@@ -629,6 +642,10 @@ public class ZeppelinServer implements AutoCloseable {
     setupNotebookServer(webApp);
   }
 
+  private static boolean isNewUiDefault(ZeppelinConfiguration zConf) {
+    return zConf.getDefaultUi() == DEFAULT_UI.NEW;
+  }
+
   @Override
   public void close() throws Exception {
     shutdown();
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java
index 76d8b8d711..3bab703eda 100644
--- 
a/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java
@@ -56,7 +56,7 @@ class IndexHtmlServletTest {
         .thenReturn(new URL("file:" + FILE_PATH_INDEX_HTML_ZEPPELIN_WEB));
       when(sc.getServletContext()).thenReturn(ctx);
 
-      IndexHtmlServlet servlet = new IndexHtmlServlet(zConf);
+      IndexHtmlServlet servlet = new IndexHtmlServlet(zConf, null);
       servlet.init(sc);
 
       HttpServletResponse mockResponse = mock(HttpServletResponse.class);
@@ -90,7 +90,7 @@ class IndexHtmlServletTest {
         .thenReturn(new URL("file:" + 
FILE_PATH_INDEX_HTML_ZEPPELIN_WEB_ANGULAR));
       when(sc.getServletContext()).thenReturn(ctx);
 
-      IndexHtmlServlet servlet = new IndexHtmlServlet(zConf);
+      IndexHtmlServlet servlet = new IndexHtmlServlet(zConf, null);
       servlet.init(sc);
 
       HttpServletResponse mockResponse = mock(HttpServletResponse.class);
diff --git a/zeppelin-web-angular/package.json 
b/zeppelin-web-angular/package.json
index a9dc4f4a53..383fe3d3ce 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -5,7 +5,7 @@
     "postinstall": "npm run build:projects",
     "ng": "./node_modules/.bin/ng",
     "start": "ng serve --proxy-config proxy.conf.js --extra-webpack-config 
webpack.partial.js",
-    "build": "ng build --prod --extra-webpack-config webpack.partial.js 
--base-href /",
+    "build": "ng build --prod --extra-webpack-config webpack.partial.js",
     "build:projects": "npm run build-project:sdk && npm run build-project:vis 
&& npm run build-project:helium",
     "build-helium-vis-example": " ng build --project helium-vis-example",
     "build-project:sdk": " ng build --project zeppelin-sdk",
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html 
b/zeppelin-web-angular/src/app/share/header/header.component.html
index 55b659f1f0..65376b617d 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.html
+++ b/zeppelin-web-angular/src/app/share/header/header.component.html
@@ -67,7 +67,7 @@
           <li nz-menu-item (click)="logout()">Logout</li>
         </ng-container>
         <li nz-menu-divider></li>
-        <li nz-menu-item><a href="/classic">Switch to Classic UI</a></li>
+        <li nz-menu-item><a [href]="classicUiHref">Switch to Classic 
UI</a></li>
       </ul>
     </nz-dropdown-menu>
   </div>
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts 
b/zeppelin-web-angular/src/app/share/header/header.component.ts
index b4c20c242c..ce0bc901b7 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.ts
+++ b/zeppelin-web-angular/src/app/share/header/header.component.ts
@@ -34,6 +34,7 @@ export class HeaderComponent extends MessageListenersManager 
implements OnInit,
   connectStatus = 'error';
   noteListVisible = false;
   queryStr: string | null = null;
+  classicUiHref: string;
 
   about() {
     this.nzModalService.create({
@@ -69,6 +70,7 @@ export class HeaderComponent extends MessageListenersManager 
implements OnInit,
     private cdr: ChangeDetectorRef
   ) {
     super(messageService);
+    this.classicUiHref = this.resolveClassicUiHref();
   }
 
   ngOnInit() {
@@ -98,4 +100,12 @@ export class HeaderComponent extends 
MessageListenersManager implements OnInit,
     this.destroy$.complete();
     super.ngOnDestroy();
   }
+
+  private resolveClassicUiHref() {
+    if (location.pathname === '/') {
+      return '/classic';
+    } else {
+      return '/';
+    }
+  }
 }
diff --git a/zeppelin-web-angular/src/index.html 
b/zeppelin-web-angular/src/index.html
index 9ad5caa094..f0c70594df 100644
--- a/zeppelin-web-angular/src/index.html
+++ b/zeppelin-web-angular/src/index.html
@@ -17,7 +17,6 @@
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" href="./assets/images/zeppelin.png" type="image/x-icon">
   <title>Zeppelin</title>
-  <base href="/">
 </head>
 <body>
 <zeppelin-root>
@@ -44,6 +43,14 @@
         "HTML-CSS": { availableFonts: ["TeX"] },
         messageStyle: "none"
       }
+      const origin = window.location.origin;
+      const pathname = window.location.pathname;
+      config.root = window.location.origin + (
+        // remove trailing slash
+        pathname.charAt(pathname.length - 1) === '/' ?
+          pathname.slice(0, -1) :
+          pathname
+      );
       MathJax.Hub.Config(config);
     </script>
 </body>
diff --git a/zeppelin-web/src/components/navbar/navbar.controller.js 
b/zeppelin-web/src/components/navbar/navbar.controller.js
index 9713e50207..503b9cd9aa 100644
--- a/zeppelin-web/src/components/navbar/navbar.controller.js
+++ b/zeppelin-web/src/components/navbar/navbar.controller.js
@@ -270,6 +270,14 @@ function NavCtrl($scope, $rootScope, $http, $routeParams, 
$location,
     }
   });
 
+  $scope.resolveNewUiHref = function() {
+    if (location.pathname === '/') {
+      return '/new';
+    } else {
+      return '/';
+    }
+  };
+
   $rootScope.isRevisionSupported = function() {
     return revisionSupported;
   };
diff --git a/zeppelin-web/src/components/navbar/navbar.html 
b/zeppelin-web/src/components/navbar/navbar.html
index 990da03cd5..cfda971f71 100644
--- a/zeppelin-web/src/components/navbar/navbar.html
+++ b/zeppelin-web/src/components/navbar/navbar.html
@@ -106,7 +106,7 @@ limitations under the License.
               <li ng-if="ticket.principal && ticket.principal !== 'anonymous'" 
role="separator" style="margin: 5px 0;" class="divider"></li>
               <li ng-if="ticket.principal && ticket.principal !== 
'anonymous'"><a ng-click="navbar.logout()">Logout</a></li>
               <li role="separator" style="margin: 5px 0;" class="divider"></li>
-              <li><a href="/">Switch to Default UI</a></li>
+              <li><a ng-href="{{ resolveNewUiHref() }}">Switch to Default 
UI</a></li>
             </ul>
           </div>
         </li>
diff --git a/zeppelin-web/src/index.html b/zeppelin-web/src/index.html
index a149af0db6..9cb60c3f82 100644
--- a/zeppelin-web/src/index.html
+++ b/zeppelin-web/src/index.html
@@ -159,7 +159,14 @@ limitations under the License.
       }
       // add root only if it's not dev mode
       if (Number(location.port) !== WEB_PORT) {
-        config.root = '.';
+        const origin = window.location.origin;
+        const pathname = window.location.pathname;
+        config.root = window.location.origin + (
+          // remove trailing slash
+          pathname.charAt(pathname.length - 1) === '/' ?
+            pathname.slice(0, -1) :
+            pathname
+        );
       }
       MathJax.Hub.Config(config);
     </script>

Reply via email to