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

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 6cf83327d46 UI: Drop the loading spinner for base React plugins 
(#74762)
6cf83327d46 is described below

commit 6cf83327d4687e121f6b2e332db300a7ce3491a3
Author: Julian LaNeve <[email protected]>
AuthorDate: Thu Oct 15 08:44:43 2026 -0400

    UI: Drop the loading spinner for base React plugins (#74762)
    
    A plugin with destination "base" renders above the content of every
    page. While its bundle loads, ReactPlugin's Suspense fallback put a bare
    spinner in the top left corner, so every full page load showed a stray
    spinner until the bundle arrived. Base plugins now render nothing until
    they are ready. Plugins on other destinations keep the spinner, since
    they fill a page or tab that would otherwise be empty.
---
 .../src/airflow/ui/src/pages/ReactPlugin.test.tsx       | 17 +++++++++++++++++
 airflow-core/src/airflow/ui/src/pages/ReactPlugin.tsx   |  4 +++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/airflow-core/src/airflow/ui/src/pages/ReactPlugin.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/ReactPlugin.test.tsx
index 6878743c55c..adbf65ee8ce 100644
--- a/airflow-core/src/airflow/ui/src/pages/ReactPlugin.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/ReactPlugin.test.tsx
@@ -189,3 +189,20 @@ describe("loadPlugin", () => {
     expect(component).not.toBe(componentA);
   });
 });
+
+const loading = (destination: ReactAppResponse["destination"]) =>
+  ({ bundle_url: "http://localhost/never-loaded.js";, destination, name: 
"Unloaded" }) as ReactAppResponse;
+
+describe("ReactPlugin loading fallback", () => {
+  it("shows a spinner while a page plugin's bundle loads", () => {
+    const { container } = render(<ReactPlugin reactApp={loading("dag")} />, { 
wrapper: Wrapper });
+
+    expect(container.querySelector(".chakra-spinner")).toBeInTheDocument();
+  });
+
+  it("shows nothing while a base plugin's bundle loads", () => {
+    const { container } = render(<ReactPlugin reactApp={loading("base")} />, { 
wrapper: Wrapper });
+
+    expect(container.querySelector(".chakra-spinner")).not.toBeInTheDocument();
+  });
+});
diff --git a/airflow-core/src/airflow/ui/src/pages/ReactPlugin.tsx 
b/airflow-core/src/airflow/ui/src/pages/ReactPlugin.tsx
index f454b6c806c..3d7b55a2d92 100644
--- a/airflow-core/src/airflow/ui/src/pages/ReactPlugin.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/ReactPlugin.tsx
@@ -150,9 +150,11 @@ export const ReactPlugin = ({ reactApp }: { readonly 
reactApp: ReactAppResponse
   // Otherwise, lazy-load the bundle once. When it resolves, it must set a 
function component
   // under globalThis[reactApp.name], which we then use as the default export.
   const LazyPlugin = lazy(() => loadPlugin(reactApp));
+  // A base plugin sits above every page, so a spinner there shows on every 
full page load.
+  const fallback = reactApp.destination === "base" ? null : <Spinner />;
 
   return (
-    <Suspense fallback={<Spinner />}>
+    <Suspense fallback={fallback}>
       <LazyPlugin {...pluginProps} />
     </Suspense>
   );

Reply via email to