diff --git a/airflow/ui/src/main.tsx b/airflow/ui/src/main.tsx index 964e6e32b9b5a..b61a2d2ed1d17 100644 --- a/airflow/ui/src/main.tsx +++ b/airflow/ui/src/main.tsx @@ -17,7 +17,7 @@ * under the License. */ import { ChakraProvider, defaultSystem } from "@chakra-ui/react"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClientProvider } from "@tanstack/react-query"; import axios, { type AxiosError } from "axios"; import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; @@ -27,22 +27,7 @@ import { ColorModeProvider } from "src/context/colorMode"; import { TimezoneProvider } from "src/context/timezone"; import { router } from "src/router"; -const queryClient = new QueryClient({ - defaultOptions: { - mutations: { - retry: 1, - retryDelay: 500, - }, - queries: { - initialDataUpdatedAt: new Date().setMinutes(-6), // make sure initial data is already expired - refetchOnMount: true, // Refetches stale queries, not "always" - refetchOnWindowFocus: false, - retry: 1, - retryDelay: 500, - staleTime: 5 * 60 * 1000, // 5 minutes - }, - }, -}); +import { queryClient } from "./queryClient"; // redirect to login page if the API responds with unauthorized or forbidden errors axios.interceptors.response.use( diff --git a/airflow/ui/src/queries/useDags.tsx b/airflow/ui/src/queries/useDags.tsx index a19592796d31e..32f01d6751472 100644 --- a/airflow/ui/src/queries/useDags.tsx +++ b/airflow/ui/src/queries/useDags.tsx @@ -25,13 +25,6 @@ import type { DAGWithLatestDagRunsResponse, } from "openapi/requests/types.gen"; -const queryOptions = { - refetchOnMount: true, - refetchOnReconnect: false, - refetchOnWindowFocus: false, - staleTime: 5 * 60 * 1000, -}; - export type DagWithLatest = { last_run_start_date: string; } & DAGWithLatestDagRunsResponse; @@ -50,13 +43,8 @@ export const useDags = ( tags?: Array; } = {}, ) => { - const offsetDefined = - searchParams.offset === undefined ? false : !isNaN(searchParams.offset); - const { data, error, isFetching, isLoading } = useDagServiceGetDags( - searchParams, - undefined, - { ...queryOptions, enabled: offsetDefined }, - ); + const { data, error, isFetching, isLoading } = + useDagServiceGetDags(searchParams); const { orderBy, ...runsParams } = searchParams; const { @@ -64,14 +52,10 @@ export const useDags = ( error: runsError, isFetching: isRunsFetching, isLoading: isRunsLoading, - } = useDagsServiceRecentDagRuns( - { - ...runsParams, - dagRunsLimit: 14, - }, - undefined, - { ...queryOptions, enabled: offsetDefined }, - ); + } = useDagsServiceRecentDagRuns({ + ...runsParams, + dagRunsLimit: 14, + }); const dags = (data?.dags ?? []).map((dag) => { const dagWithRuns = runsData?.dags.find( diff --git a/airflow/ui/src/queryClient.ts b/airflow/ui/src/queryClient.ts new file mode 100644 index 0000000000000..fac657943dc4f --- /dev/null +++ b/airflow/ui/src/queryClient.ts @@ -0,0 +1,36 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 { QueryClient } from "@tanstack/react-query"; + +export const queryClient = new QueryClient({ + defaultOptions: { + mutations: { + retry: 1, + retryDelay: 500, + }, + queries: { + initialDataUpdatedAt: new Date().setMinutes(-6), // make sure initial data is already expired + refetchOnMount: true, // Refetches stale queries, not "always" + refetchOnWindowFocus: false, + retry: 1, + retryDelay: 500, + staleTime: 5 * 60 * 1000, // 5 minutes + }, + }, +}); diff --git a/airflow/ui/src/router.tsx b/airflow/ui/src/router.tsx index b9e0e23dad7c1..a32337317bd50 100644 --- a/airflow/ui/src/router.tsx +++ b/airflow/ui/src/router.tsx @@ -16,8 +16,11 @@ * specific language governing permissions and limitations * under the License. */ +import { queryOptions } from "@tanstack/react-query"; import { createBrowserRouter } from "react-router-dom"; +import { UseConfigServiceGetConfigsKeyFn } from "openapi/queries"; +import { ConfigService } from "openapi/requests/services.gen"; import { BaseLayout } from "src/layouts/BaseLayout"; import { Dag } from "src/pages/Dag"; import { Code } from "src/pages/Dag/Code"; @@ -35,6 +38,7 @@ import { TaskInstance, Logs } from "src/pages/TaskInstance"; import { XCom } from "src/pages/XCom"; import { Variables } from "./pages/Variables"; +import { queryClient } from "./queryClient"; export const router = createBrowserRouter( [ @@ -106,6 +110,17 @@ export const router = createBrowserRouter( ), + // Use react router loader to ensure we have the config before any other requests are made + loader: async () => { + const data = await queryClient.ensureQueryData( + queryOptions({ + queryFn: ConfigService.getConfigs, + queryKey: UseConfigServiceGetConfigsKeyFn(), + }), + ); + + return data; + }, path: "/", }, ],