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

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


The following commit(s) were added to refs/heads/main by this push:
     new 29d40aa640 [#12200] fix(web-v2): Gate metalake fetch until OAuth token 
is ready (#12203)
29d40aa640 is described below

commit 29d40aa6404606b0caf99dcbf9366854f2cacfea
Author: Phước <[email protected]>
AuthorDate: Wed Jul 29 17:29:33 2026 +0700

    [#12200] fix(web-v2): Gate metalake fetch until OAuth token is ready 
(#12203)
    
    ### What changes were proposed in this pull request?
    
    This PR updates the V2 Web UI metalakes page to avoid fetching metalakes
    before authentication bootstrap is ready.
    
    The metalake store reset still runs when the page mounts, but the
    metalake fetch now waits until the auth type is known. For OAuth/OIDC
    authentication, it also waits until the OAuth token exists in Redux
    before calling the metalake API.
    
    ### Why are the changes needed?
    
    Before this change, the metalakes page called `fetchMetalakes()`
    immediately on mount. In OAuth/OIDC mode, this could race with the
    asynchronous auth bootstrap after login. The page could request metalake
    data before the access token was available, causing unauthorized API
    calls, redirects back to login, or an empty metalakes page.
    
    Fix: #12200
    
    ### Does this PR introduce _any_ user-facing change?
    
    No user-facing API or configuration changes.
    
    For OAuth/OIDC users, the V2 Web UI avoids making the metalake API
    request until the OAuth token is ready.
    
    ### How was this patch tested?
    
    Ran formatter for the V2 Web UI:
    
    ```bash
    cd web-v2/web && pnpm format
    ```
    
    Verified the PR diff is minimal and only changes:
    
    ```text
    web-v2/web/src/app/metalakes/page.js
    ```
    
    Co-authored-by: phuocho <[email protected]>
---
 web-v2/web/src/app/metalakes/page.js        | 12 ++++++++++--
 web-v2/web/src/lib/store/metalakes/index.js | 30 ++++++++++++++++++++---------
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/web-v2/web/src/app/metalakes/page.js 
b/web-v2/web/src/app/metalakes/page.js
index 1f9c468846..cab7854dd8 100644
--- a/web-v2/web/src/app/metalakes/page.js
+++ b/web-v2/web/src/app/metalakes/page.js
@@ -70,7 +70,8 @@ const MetalakeList = () => {
   const [search, setSearch] = useState('')
   const [ownerRefreshKey, setOwnerRefreshKey] = useState(0)
   const auth = useAppSelector(state => state.auth)
-  const { serviceAdmins, authUser, anthEnable } = auth
+  const { serviceAdmins, authUser, anthEnable, authType, authToken } = auth
+  const isAuthReady = authType && (authType !== 'oauth' || !!authToken)
   const admins = normalizeServiceAdmins(serviceAdmins)
   const isServiceAdmin = admins.includes(authUser?.name)
   const dispatch = useAppDispatch()
@@ -79,9 +80,16 @@ const MetalakeList = () => {
 
   useEffect(() => {
     dispatch(resetMetalakeStore())
-    dispatch(fetchMetalakes())
   }, [dispatch])
 
+  useEffect(() => {
+    if (!isAuthReady) {
+      return
+    }
+
+    dispatch(fetchMetalakes())
+  }, [dispatch, isAuthReady])
+
   useEffect(() => {
     const filteredData = store.metalakes
       .filter(i => i.name.toLowerCase().includes(search.toLowerCase()))
diff --git a/web-v2/web/src/lib/store/metalakes/index.js 
b/web-v2/web/src/lib/store/metalakes/index.js
index 2f6cd2c4a5..55566d6973 100644
--- a/web-v2/web/src/lib/store/metalakes/index.js
+++ b/web-v2/web/src/lib/store/metalakes/index.js
@@ -108,19 +108,31 @@ const mergeWithViewNodes = ({ tree, key, entities }) => {
   return _.uniqBy([...subSchemas, ...tables, ...functions, ...entities], 'key')
 }
 
-export const fetchMetalakes = createAsyncThunk('appMetalakes/fetchMetalakes', 
async (params, { getState }) => {
-  const [err, res] = await to(getMetalakesApi())
+const isAuthReady = state => {
+  const { authType, authToken } = state.auth
 
-  if (err || !res) {
-    throw new Error(err)
-  }
+  return !!authType && (authType !== 'oauth' || !!authToken)
+}
 
-  const { metalakes } = res
+export const fetchMetalakes = createAsyncThunk(
+  'appMetalakes/fetchMetalakes',
+  async () => {
+    const [err, res] = await to(getMetalakesApi())
 
-  metalakes.sort((a, b) => new Date(b.audit.createTime) - new 
Date(a.audit.createTime))
+    if (err || !res) {
+      throw new Error(err)
+    }
 
-  return { metalakes }
-})
+    const { metalakes } = res
+
+    metalakes.sort((a, b) => new Date(b.audit.createTime) - new 
Date(a.audit.createTime))
+
+    return { metalakes }
+  },
+  {
+    condition: (_, { getState }) => isAuthReady(getState())
+  }
+)
 
 export const createMetalake = createAsyncThunk('appMetalakes/createMetalake', 
async (data, { getState, dispatch }) => {
   const [err, res] = await to(createMetalakeApi(data))

Reply via email to