From b9c899bab74697333e56f9bc4d46f0b7b83f8922 Mon Sep 17 00:00:00 2001 From: rayshrey <121871912+rayshrey@users.noreply.github.com> Date: Wed, 26 Aug 2026 05:44:26 -0700 Subject: [PATCH 1/3] SOLR-18347: Guard null core selection in Admin UI --- .../src/test/org/apache/solr/webapp/AdminUiTestBase.java | 6 ------ solr/webapp/web/js/angular/app.js | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java index 5d0ea91fe9f4..ac471487420c 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java @@ -537,12 +537,6 @@ protected static void assertNoSevereConsoleErrors(String... allowedSubstrings) { // the ui-grid icon font referenced from ui-grid.min.css is not shipped with // the webapp at all, so it 404s in production too .filter(entry -> !entry.getMessage().contains("fonts/ui-grid")) - // benign race in the shared menu code: showCore() fires with a null core - // while the per-collection menu resolves after navigation - .filter( - entry -> - !(entry.getMessage().contains("reading 'name'") - && entry.getMessage().contains("showCore"))) .toList(); assertTrue("Severe browser console errors: " + severe, severe.isEmpty()); } diff --git a/solr/webapp/web/js/angular/app.js b/solr/webapp/web/js/angular/app.js index 1ff0cb824f2d..9e929407a336 100644 --- a/solr/webapp/web/js/angular/app.js +++ b/solr/webapp/web/js/angular/app.js @@ -628,7 +628,9 @@ solrAdminApp.controller('MainController', function($scope, $route, $rootScope, $ } $scope.showCore = function(core) { - $location.url("/" + core.name + "/core-overview"); + if (core) { + $location.url("/" + core.name + "/core-overview"); + } } $scope.showCollection = function(collection) { From e7e66a51b5232bd71ef756584c060a3f417d5ebb Mon Sep 17 00:00:00 2001 From: rayshrey <121871912+rayshrey@users.noreply.github.com> Date: Wed, 26 Aug 2026 06:36:07 -0700 Subject: [PATCH 2/3] SOLR-18347: Fix remaining Admin UI defects --- .../solr-18347-admin-ui-defects.yml | 9 ++++ dev-docs/admin-ui-tests.md | 19 ------- .../solr/handler/PingRequestHandler.java | 5 +- .../solr/handler/PingRequestHandlerTest.java | 4 ++ solr/webapp/build.gradle | 31 ------------ .../webapp/AdminUiCollectionScreensTest.java | 4 +- .../webapp/AdminUiCollectionsScreenTest.java | 10 +++- .../AdminUiCoreAdminStandaloneTest.java | 4 +- .../webapp/AdminUiSchemaDesignerTest.java | 38 ++------------ .../apache/solr/webapp/AdminUiSmokeTest.java | 4 +- .../apache/solr/webapp/AdminUiTestBase.java | 50 +------------------ solr/webapp/web/index.html | 1 - .../web/js/angular/controllers/collections.js | 23 +++++---- .../js/angular/controllers/core-overview.js | 10 ++-- .../js/angular/controllers/schema-designer.js | 12 +++-- solr/webapp/web/js/angular/services.js | 6 --- solr/webapp/web/partials/collections.html | 3 +- solr/webapp/web/partials/schema-designer.html | 4 +- 18 files changed, 66 insertions(+), 171 deletions(-) create mode 100644 changelog/unreleased/solr-18347-admin-ui-defects.yml diff --git a/changelog/unreleased/solr-18347-admin-ui-defects.yml b/changelog/unreleased/solr-18347-admin-ui-defects.yml new file mode 100644 index 000000000000..80f18ea21e8a --- /dev/null +++ b/changelog/unreleased/solr-18347-admin-ui-defects.yml @@ -0,0 +1,9 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Fix five Admin UI defects found by Selenium testing +type: fixed # added, changed, fixed, deprecated, removed, dependency_update, security, other +authors: + - name: Shrey Narayan + nick: NextbrickInc +links: + - name: SOLR-18347 + url: https://issues.apache.org/jira/browse/SOLR-18347 diff --git a/dev-docs/admin-ui-tests.md b/dev-docs/admin-ui-tests.md index 73ad2a9f65b7..c88bf05786bd 100644 --- a/dev-docs/admin-ui-tests.md +++ b/dev-docs/admin-ui-tests.md @@ -44,28 +44,9 @@ deliberately does not do. ## Known limitations -- The generated js-client bundle (`libs/solr/index.js`) only exists inside the - built WAR, not in the source tree tests serve from, so the build hands its - location to the test JVM in `tests.ui.jsclient.bundle`. The bundle (and its - node/npm toolchain) is only built when `-Ptests.selenium=true` enables the - tests, keeping node off the default test build chain. With the js-client - build turned off (`-PdisableJsClient=true`) the bundle cannot be built, so - the build disables these tests with a warning — and fails with an error if - `-Ptests.selenium=true` was passed as well. - Every test cluster in the JVM registers a log-watcher appender under the same name in the shared log4j config, so a later cluster's watcher can be blind; the events-viewer test detects this via the API and skips itself. -- The shared menu code logs a benign - `TypeError: Cannot read properties of null (reading 'name')` from - `$scope.showCore` while the per-collection menu resolves (filtered in the - console-error assertion; tracked in - [SOLR-18347](https://issues.apache.org/jira/browse/SOLR-18347)). -- The core overview ping widget answers 503 when the configset has no - healthcheck file (allowed in the affected tests; tracked in - [SOLR-18347](https://issues.apache.org/jira/browse/SOLR-18347)). -- The Schema Designer's backend transiently fails its own prep/analyze calls - with "version mismatch, retry" and recovers via its retry dialog; its API - errors are excluded from the console-error assertion. - ASF Jenkins jobs do not pass `-Ptests.selenium=true`, so these tests do not run there (a nightly job could opt in if its build nodes have a browser). In CI they run via the GitHub Actions workflow diff --git a/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java index f7eaa97db78b..ba7ebd2d6889 100644 --- a/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/PingRequestHandler.java @@ -213,10 +213,7 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw break; case STATUS: if (healthcheck == null) { - SolrException e = - new SolrException( - SolrException.ErrorCode.SERVICE_UNAVAILABLE, "healthcheck not configured"); - rsp.setException(e); + rsp.add("status", "not_configured"); } else { rsp.add("status", isPingDisabled() ? "disabled" : "enabled"); } diff --git a/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java index 3f151e51efca..4180be913579 100644 --- a/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java @@ -85,6 +85,10 @@ public void testPingWithNoHealthCheck() throws Exception { rsp = makeRequest(handler, req("action", "ping")); assertEquals("OK", rsp.getValues().get("status")); + + rsp = makeRequest(handler, req("action", "status")); + assertEquals("not_configured", rsp.getValues().get("status")); + assertNull(rsp.getException()); } public void testEnablingServer() throws Exception { diff --git a/solr/webapp/build.gradle b/solr/webapp/build.gradle index 184391590c56..4f6831bf659b 100644 --- a/solr/webapp/build.gradle +++ b/solr/webapp/build.gradle @@ -37,7 +37,6 @@ configurations { war {} serverLib solrCore - generatedJSClientBundle generatedUIBundle } @@ -47,10 +46,6 @@ dependencies { solrCore project(":solr:core") implementation(configurations.solrCore - configurations.serverLib) - if (gradle.ext.withJsClient) { - generatedJSClientBundle project(path: ":solr:webapp:js-client", configuration: "jsClientBundle") - } - if (gradle.ext.withUiModule) { generatedUIBundle project(path: ":solr:ui", configuration: "wasmJsUIBundle") } @@ -88,37 +83,11 @@ tasks.withType(Test).configureEach { systemProperty 'tests.selenium.chrome.binary', chromeBinary } - // the Admin UI tests exercise the generated js-client bundle; a stub would only grow - // stale as the UI adopts more of the v2 API, so without the bundle the tests cannot - // run at all. The bundle (and thereby its node/npm toolchain) is only wired in when - // the tests are explicitly enabled, keeping node off the default test build chain. - def seleniumEnabled = Boolean.parseBoolean(Objects.toString(propertyOrDefault('tests.selenium', 'false'))) - if (seleniumEnabled && gradle.ext.withJsClient) { - def jsClientBundle = configurations.generatedJSClientBundle - inputs.files(jsClientBundle).withPropertyName('jsClientBundle') - doFirst { - systemProperty 'tests.ui.jsclient.bundle', new File(jsClientBundle.singleFile, 'index.js') - } - } else if (seleniumEnabled) { - doFirst { - throw new GradleException('Cannot run the Admin UI tests (-Ptests.selenium=true): ' + - '-PdisableJsClient=true excludes the js-client bundle they need. Drop one of the two flags.') - } - } else if (!gradle.ext.withJsClient) { - enabled = false - logger.warn('NOTE: :solr:webapp tests are disabled because -PdisableJsClient=true ' + - 'excludes the js-client bundle the Admin UI tests need.') - } } war { from("web") - // note: nonetheless may be disabled, copying nothing - from(configurations.generatedJSClientBundle, { - into "libs/solr" - }) - // note: nonetheless may be disabled, copying nothing from(configurations.generatedUIBundle, { into "ui" diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionScreensTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionScreensTest.java index f758d46e11b4..b4e82fb54578 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionScreensTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionScreensTest.java @@ -101,7 +101,7 @@ public void testCoreOverviewShowsStats() { openPage(coreName + "/core-overview", By.id("dashboard")); waitForPageContains("Num Docs"); waitForPageContains(Integer.toString(NUM_DOCS)); - // the ping widget answers 503 when the configset has no healthcheck file - assertNoSevereConsoleErrors("/admin/ping"); + waitForPageContains("Ping request handler is not configured with a healthcheck file."); + assertNoSevereConsoleErrors(); } } diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java index 8dad9b0be8a1..e8e44ad6ebd7 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java @@ -142,8 +142,8 @@ public void testAddAndDeleteReplicaViaUi() throws Exception { @Test public void testReloadCollectionViaUi() throws Exception { - // reloading resets the core's start time; that proves the action end-to-end, - // unlike the UI success indicator which only flashes for a second + // Reloading resets the core's start time, and the success state remains visible long enough + // for a user to notice instead of disappearing after one second. String coreName = coreNameOnNode0(COLLECTION); Object startTimeBefore = coreStartTime(coreName); @@ -152,6 +152,12 @@ public void testReloadCollectionViaUi() throws Exception { waitUntil( "core start time should change after reload", () -> !startTimeBefore.equals(coreStartTime(coreName))); + WebElement reload = waitFor(By.cssSelector("#reload.success")); + assertEquals("Reloaded", reload.getText()); + Thread.sleep(1500); + assertTrue( + "reload success should remain visible", reload.getAttribute("class").contains("success")); + assertEquals("Reloaded", reload.getText()); assertNoSevereConsoleErrors(); } diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCoreAdminStandaloneTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCoreAdminStandaloneTest.java index 0508fd636e79..ea801c7d8243 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCoreAdminStandaloneTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCoreAdminStandaloneTest.java @@ -63,8 +63,8 @@ public void testStandaloneMenus() { openPage("swapa/core-overview", By.id("dashboard")); waitFor(By.cssSelector("#core-menu .query")); waitFor(By.cssSelector("#core-menu .replication")); - // the ping widget answers 503 when the configset has no healthcheck file - assertNoSevereConsoleErrors("/admin/ping"); + waitForPageContains("Ping request handler is not configured with a healthcheck file."); + assertNoSevereConsoleErrors(); } @Test diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSchemaDesignerTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSchemaDesignerTest.java index 85a76aec800c..670a9df12b37 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSchemaDesignerTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSchemaDesignerTest.java @@ -16,7 +16,6 @@ */ package org.apache.solr.webapp; -import org.apache.lucene.tests.util.LuceneTestCase; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -25,11 +24,9 @@ * Happy-path test of the Schema Designer screen: create a new schema, paste a sample document and * let the designer analyze it. * - *
AwaitsFix: the designer backend transiently fails its own prep/analyze calls ("version - * mismatch, retry", "Error loading solr config") when driven at automation speed, making this test - * flaky even with retries. + *
The Analyze action remains disabled until creation of the mutable schema has completed, so a + * fast user cannot race the prep and analyze requests. */ -@LuceneTestCase.AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-18347") public class AdminUiSchemaDesignerTest extends AdminUiTestBase { @Test @@ -47,34 +44,9 @@ public void testDesignSchemaFromSampleDocument() throws Exception { WebElement sampleDocs = waitFor(By.cssSelector("#sample-docs textarea#document")); sampleDocs.clear(); sampleDocs.sendKeys("[{\"id\":\"1\",\"designer_title\":\"Hello Designer\"}]"); - click(By.id("analyze")); + click(By.cssSelector("#analyze:not([disabled])")); - // the analyzed schema lists the field derived from the sample doc. The designer - // backend transiently fails its own calls ("version mismatch, retry", "Error - // loading solr config") and surfaces an error dialog - dismiss it and analyze - // again, with a generous budget since each round trips several requests - long deadlineNanos = System.nanoTime() + WAIT_TIMEOUT.multipliedBy(3).toNanos(); - boolean analyzed = false; - while (!analyzed && System.nanoTime() < deadlineNanos) { - analyzed = driver.getPageSource().contains("designer_title"); - if (!analyzed) { - for (String dismissButton : new String[] {"Reload Schema", "OK"}) { - driver.findElements(By.xpath("//button[contains(., '" + dismissButton + "')]")).stream() - .filter(WebElement::isDisplayed) - .findFirst() - .ifPresent(WebElement::click); - } - driver.findElements(By.id("analyze")).stream() - .filter(WebElement::isDisplayed) - .findFirst() - .ifPresent(WebElement::click); - Thread.sleep(500); - } - } - assertTrue("Analyzed schema should list the sample doc field", analyzed); - // the designer's own API calls (prep/analyze/luke against its temp core) error - // transiently while it persists and reloads the schema - it recovers via its retry - // dialog, so only unrelated console errors fail the test - assertNoSevereConsoleErrors("schema-designer/", "._designer_"); + waitForPageContains("designer_title"); + assertNoSevereConsoleErrors(); } } diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSmokeTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSmokeTest.java index 5dfc5b2a4517..a20059160181 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSmokeTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiSmokeTest.java @@ -91,9 +91,7 @@ public void testCoreScreens() { coreName + "/plugins", By.id("plugins"), coreName + "/segments", By.id("segments")); screens.forEach(this::smoke); - // the ping widget on the overview answers 503 when no healthcheck file is configured, - // as is the case for the _default configset - smoke(coreName + "/core-overview", By.id("dashboard"), "/admin/ping"); + smoke(coreName + "/core-overview", By.id("dashboard")); } private void smoke(String route, By anchor) { diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java index ac471487420c..89718660c5f8 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java @@ -19,9 +19,6 @@ import com.carrotsearch.randomizedtesting.ThreadFilter; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.lang.invoke.MethodHandles; @@ -51,7 +48,6 @@ import org.apache.solr.embedded.JettySolrRunner; import org.apache.solr.util.ExternalPaths; import org.apache.solr.util.SeleniumTest; -import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -128,39 +124,6 @@ public abstract class AdminUiTestBase extends SolrCloudTestCase { /** The standalone node backing {@link #adminApi} when {@link #standaloneMode} is set. */ protected static JettySolrRunner standaloneJetty; - /** - * Serves the generated js-client bundle the AngularJS UI expects at {@code libs/solr/index.js}: - * its {@code CollectionsV2} service fails to instantiate without the {@code solrApi} global, - * taking the whole Collections screen down with it. The bundle is built by {@code - * :solr:webapp:js-client} and its location handed to the test JVM in {@code - * tests.ui.jsclient.bundle}; it only exists inside the built webapp, not in the source tree tests - * serve from. - */ - public static class JsClientServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - resp.setContentType("text/javascript"); - Files.copy(jsClientBundlePath(), resp.getOutputStream()); - } - } - - /** - * The generated js-client bundle: handed to us by the build in {@code tests.ui.jsclient.bundle}, - * with the js-client build's output location as a fallback so tests can also run from an IDE - * (after a Gradle build has produced the bundle). Null when unavailable. - */ - private static Path jsClientBundlePath() { - String path = EnvUtils.getProperty("tests.ui.jsclient.bundle"); - if (path == null && ExternalPaths.SOURCE_HOME == null) { - return null; - } - Path bundle = - path != null - ? Path.of(path) - : ExternalPaths.SOURCE_HOME.resolve("webapp/js-client/build/jsClientBundle/index.js"); - return Files.isReadable(bundle) ? bundle : null; - } - /** Ignores threads spawned by Selenium and the JDK http client it uses. */ public static class WebDriverThreadsFilter implements ThreadFilter { @Override @@ -189,12 +152,6 @@ public static void startClusterAndBrowser() throws Exception { "Selenium tests are enabled (-Ptests.selenium=true) but no Chrome/Chromium binary was" + " found; install one or point -Dtests.selenium.chrome.binary at it"); } - if (jsClientBundlePath() == null) { - fail( - "No generated js-client bundle available; the Gradle build wires it via" - + " tests.ui.jsclient.bundle (is -PdisableJsClient=true set?)"); - } - // metrics are off by default in test clusters, but UI screens (e.g. Plugins) need them; // restored after the class by SolrTestCase's SystemPropertiesRestoreRule System.setProperty("metricsEnabled", "true"); @@ -241,12 +198,9 @@ protected static void ensureCloudCluster() { } } - /** Configures a Jetty node to serve the Admin UI plus the js-client bundle. */ + /** Configures a Jetty node to serve the Admin UI. */ protected static void configureJettyForUi(JettyConfig.Builder jetty) { - jetty - .enableAdminUi(true) - // exact-path mapping takes precedence over the static /libs/* servlet - .withServlet(new ServletHolder(new JsClientServlet()), "/libs/solr/index.js"); + jetty.enableAdminUi(true); } @AfterClass diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index 46535d6b7427..ca7703b86909 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -68,7 +68,6 @@ - diff --git a/solr/webapp/web/js/angular/controllers/collections.js b/solr/webapp/web/js/angular/controllers/collections.js index 830290a18069..906251b43556 100644 --- a/solr/webapp/web/js/angular/controllers/collections.js +++ b/solr/webapp/web/js/angular/controllers/collections.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CollectionsController', - function($scope, $routeParams, $location, $timeout, Collections, CollectionsV2, Zookeeper, Constants, ConfigSets){ + function($scope, $routeParams, $location, $timeout, Collections, Zookeeper, Constants, ConfigSets){ $scope.resetMenu("collections", Constants.IS_ROOT_PAGE); $scope.refresh = function() { @@ -215,16 +215,17 @@ solrAdminApp.controller('CollectionsController', alert("No collection selected."); return; } - CollectionsV2.reloadCollection($scope.collection.name, function(error, data,response) { - if (error) { - $scope.reloadFailure = true; - $timeout(function() {$scope.reloadFailure=false}, 1000); - $location.path("/~collections"); - } else { - $scope.reloadSuccess = true; - $timeout(function() {$scope.reloadSuccess=false}, 1000); - } - }); + $scope.reloadSuccess = false; + $scope.reloadFailure = false; + Collections.reload( + {name: $scope.collection.name}, + function() { + $scope.reloadSuccess = true; + }, + function() { + $scope.reloadFailure = true; + } + ); }; $scope.toggleAddReplica = function(shard) { diff --git a/solr/webapp/web/js/angular/controllers/core-overview.js b/solr/webapp/web/js/angular/controllers/core-overview.js index 4c97e6d12b07..75b8fdb06e9b 100644 --- a/solr/webapp/web/js/angular/controllers/core-overview.js +++ b/solr/webapp/web/js/angular/controllers/core-overview.js @@ -56,14 +56,16 @@ function($scope, $rootScope, $routeParams, Luke, CoreInfo, Update, Replication, $scope.refreshPing = function() { Ping.status({core: $routeParams.core}, function(data) { - if (data.error) { + if (data.status == "not_configured") { $scope.healthcheckStatus = false; - if (data.error.code == 503) { - $scope.healthcheckMessage = 'Ping request handler is not configured with a healthcheck file.'; - } + $scope.healthcheckMessage = 'Ping request handler is not configured with a healthcheck file.'; } else { + delete $scope.healthcheckMessage; $scope.healthcheckStatus = data.status == "enabled"; } + }, function(error) { + $scope.healthcheckStatus = false; + $scope.healthcheckMessage = error.data && error.data.error ? error.data.error.msg : 'Unable to read ping status.'; }); }; diff --git a/solr/webapp/web/js/angular/controllers/schema-designer.js b/solr/webapp/web/js/angular/controllers/schema-designer.js index 7ec4282bb053..a2d08aa79d73 100644 --- a/solr/webapp/web/js/angular/controllers/schema-designer.js +++ b/solr/webapp/web/js/angular/controllers/schema-designer.js @@ -24,6 +24,7 @@ solrAdminApp.controller('SchemaDesignerController', function ($scope, $timeout, $scope.sortableFields = []; $scope.hlFields = []; $scope.types = []; + $scope.preparingSchema = false; $scope.onWarning = function (warnMsg, warnDetails) { $scope.updateWorking = false; @@ -34,6 +35,7 @@ solrAdminApp.controller('SchemaDesignerController', function ($scope, $timeout, $scope.onError = function (errorMsg, errorCode, errorDetails) { $scope.updateWorking = false; + $scope.preparingSchema = false; delete $scope.updateStatusMessage; $scope.designerAPIError = errorMsg; if (errorDetails) { @@ -303,7 +305,9 @@ solrAdminApp.controller('SchemaDesignerController', function ($scope, $timeout, $scope.currentSchema = $scope.newSchema; $scope.sampleMessage = "Please upload or paste some sample documents to analyze for building the '" + $scope.currentSchema + "' schema."; + $scope.preparingSchema = true; SchemaDesigner.post({path: "prep", configSet: $scope.newSchema, copyFrom: $scope.copyFrom}, null, function (data) { + $scope.preparingSchema = false; $scope.initDesignerSettingsFromResponse(data); }, $scope.errorHandler); }; @@ -451,9 +455,11 @@ solrAdminApp.controller('SchemaDesignerController', function ($scope, $timeout, // re-apply the filters on the updated schema $scope.onTreeFilterOptionChanged(); - // Load the Luke schema - Luke.schema({core: data.core}, function (schema) { - Luke.raw({core: data.core}, function (index) { + // Route Luke through the temporary collection so the request reaches its + // active replica even when the Admin UI is connected to a different node. + var lukeTarget = data.tempCollection || data.core; + Luke.schema({core: lukeTarget}, function (schema) { + Luke.raw({core: lukeTarget}, function (index) { $scope.luke = mergeIndexAndSchemaData(index, schema.schema); $scope.types = Object.keys(schema.schema.types); $scope.showSchemaActions = true; diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 47c5ad2fa6ee..f249c64c69d3 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -44,12 +44,6 @@ solrAdminServices.factory('System', } }); }]) -.factory('CollectionsV2', - function() { - solrApi.ApiClient.instance.basePath = '/api'; - delete solrApi.ApiClient.instance.defaultHeaders["User-Agent"]; - return new solrApi.CollectionsApi(); - }) .factory('Collections', ['$resource', function($resource) { return $resource('admin/collections', diff --git a/solr/webapp/web/partials/collections.html b/solr/webapp/web/partials/collections.html index a05ebe7198f3..8973d31562c6 100644 --- a/solr/webapp/web/partials/collections.html +++ b/solr/webapp/web/partials/collections.html @@ -128,7 +128,8 @@ + ng-class="{success: reloadSuccess, warn: reloadFailure, disabled:!isPermitted(permissions.COLL_EDIT_PERM)}" + aria-live="polite">{{reloadSuccess ? 'Reloaded' : (reloadFailure ? 'Reload failed' : 'Reload')}}