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

mchades 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 11205b28bc [#11624][#11633][#11632] web-v2(UI): fix delete subschemas 
issue (#11654)
11205b28bc is described below

commit 11205b28bcc566bb6236dde1e7ce13cc29736ffa
Author: Qian Xia <[email protected]>
AuthorDate: Tue Jun 16 14:42:52 2026 +0800

    [#11624][#11633][#11632] web-v2(UI): fix delete subschemas issue (#11654)
    
    ### What changes were proposed in this pull request?
    <img width="2116" height="1708" alt="image"
    
src="https://github.com/user-attachments/assets/b13b259b-8f7f-4911-be85-9f138b44ebe7";
    />
    <img width="2120" height="1702" alt="image"
    
src="https://github.com/user-attachments/assets/06f682ce-8779-4d8e-9335-7078188b82f0";
    />
    
    1. fix delete subschemas issue
    2. improve subschema tree node expand icon
    
    
    ### Why are the changes needed?
    N/A
    
    Fix: #11624, #11632, #11632
    
    ### Does this PR introduce _any_ user-facing change?
    N/A
    
    ### How was this patch tested?
    manually
---
 web-v2/web/src/app/catalogs/TreeComponent.js       |  6 +-
 web-v2/web/src/app/catalogs/page.js                | 16 ++++-
 .../catalogs/rightContent/CreateSchemaDialog.js    |  6 +-
 .../entitiesContent/SchemaDetailsPage.js           | 80 +++++++++-------------
 web-v2/web/src/components/ConfirmInput.js          |  2 +-
 web-v2/web/src/lib/store/metalakes/index.js        | 25 +++++--
 web-v2/web/src/lib/utils/index.js                  |  4 +-
 7 files changed, 78 insertions(+), 61 deletions(-)

diff --git a/web-v2/web/src/app/catalogs/TreeComponent.js 
b/web-v2/web/src/app/catalogs/TreeComponent.js
index 9efa32a3ee..01ab6d4402 100644
--- a/web-v2/web/src/app/catalogs/TreeComponent.js
+++ b/web-v2/web/src/app/catalogs/TreeComponent.js
@@ -484,20 +484,20 @@ export const TreeComponent = forwardRef(function 
TreeComponent(props, ref) {
     setIsHover(null)
   }
 
-  const onLoadData = node => {
+  const onLoadData = (node, reload = false) => {
     if (node.inUse === 'false') return new Promise(resolve => resolve())
     const { key, children } = node
 
     dispatch(setLoadedNodes([...store.loadedNodes, key]))
 
     return new Promise(resolve => {
-      if (children && children.length !== 0) {
+      if (!reload && children && children.length !== 0) {
         resolve()
 
         return
       }
 
-      dispatch(setIntoTreeNodeWithFetch({ key }))
+      dispatch(setIntoTreeNodeWithFetch({ key, reload }))
 
       resolve()
     })
diff --git a/web-v2/web/src/app/catalogs/page.js 
b/web-v2/web/src/app/catalogs/page.js
index 2f4abfd744..9e8b2e5b3a 100644
--- a/web-v2/web/src/app/catalogs/page.js
+++ b/web-v2/web/src/app/catalogs/page.js
@@ -163,9 +163,19 @@ const CatalogsListPage = () => {
         }
 
         if (paramsSize === 4 && catalog && catalogType && schema) {
-          if (!store.catalogs.length) {
-            await dispatch(fetchCatalogs({ metalake }))
-            await dispatch(fetchSchemas({ metalake, catalog, catalogType }))
+          let catalogsList = store.catalogs
+          if (!catalogsList.length) {
+            const { payload } = await dispatch(fetchCatalogs({ init: true, 
metalake }))
+            catalogsList = payload?.catalogs || []
+            await dispatch(fetchSchemas({ init: true, metalake, catalog, 
catalogType }))
+          }
+          const currentCatalog = catalogsList.find(c => c.name === catalog)
+
+          const isIcebergJdbcCatalog =
+            currentCatalog?.provider === 'lakehouse-iceberg' &&
+            currentCatalog?.properties?.['catalog-backend'] === 'jdbc'
+          if (isIcebergJdbcCatalog) {
+            dispatch(fetchSchemas({ metalake, catalog, catalogType, 
parentSchema: schema }))
           }
           dispatch(fetchFunctions({ init: true, metalake, catalog, schema }))
           switch (catalogType) {
diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateSchemaDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateSchemaDialog.js
index 94fc9fb327..05b54244e6 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateSchemaDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateSchemaDialog.js
@@ -205,7 +205,11 @@ export default function CreateSchemaDialog({ ...props }) {
         } else {
           await dispatch(createSchema({ data: submitData, metalake, catalog, 
catalogType }))
         }
-        !editSchema && treeRef.current.onLoadData({ key: catalog, nodeType: 
'catalog', inUse: 'true' }, true)
+        !editSchema &&
+          treeRef.current.onLoadData(
+            { key: `{{${metalake}}}{{${catalog}}}{{${catalogType}}}`, 
nodeType: 'catalog', inUse: 'true' },
+            true
+          )
         setConfirmLoading(false)
         setOpen(false)
       })
diff --git 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js
index ab897be47c..7c837a9cbc 100644
--- 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js
+++ 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js
@@ -64,7 +64,6 @@ import {
 } from '@/lib/store/metalakes'
 import Link from 'next/link'
 import { cn } from '@/lib/utils/tailwind'
-import { to } from '@/lib/utils'
 import Loading from '@/components/Loading'
 import CreateSchemaDialog from '../CreateSchemaDialog'
 import CreateFilesetDialog from '../CreateFilesetDialog'
@@ -149,6 +148,11 @@ export default function SchemaDetailsPage() {
       return
     }
 
+    // Wait for catalogData to be loaded before checking catalog type
+    if (!catalogData) {
+      return
+    }
+
     const provider = catalogData?.provider
     const catalogBackend = catalogData?.properties?.['catalog-backend']
     const isIcebergJdbcCatalog = provider === 'lakehouse-iceberg' && 
catalogBackend === 'jdbc'
@@ -160,32 +164,18 @@ export default function SchemaDetailsPage() {
       return
     }
 
-    const loadSubSchemas = async () => {
-      const [err, res] = await to(
-        dispatch(fetchSchemas({ metalake: currentMetalake, catalog, 
catalogType, parentSchema: schema }))
-      )
-      if (err || !res) {
-        setSubSchemas([])
-
-        return
+    // Use subschemas from store
+    const nextSubSchemas = (store.subschemas || []).map(item => {
+      return {
+        ...item,
+        name: item.name,
+        key: item.name,
+        title: item.name
       }
+    })
 
-      const { schemas = [] } = res?.payload || {}
-
-      const nextSubSchemas = schemas.map(item => {
-        return {
-          ...item,
-          name: item.name,
-          key: item.name,
-          title: item.name
-        }
-      })
-
-      setSubSchemas(nextSubSchemas)
-    }
-
-    loadSubSchemas()
-  }, [currentMetalake, catalog, schema, catalogData?.provider, 
catalogData?.properties?.['catalog-backend']])
+    setSubSchemas(nextSubSchemas)
+  }, [currentMetalake, catalog, schema, catalogData, store.subschemas])
 
   useEffect(() => {
     const hasSubSchemas = subSchemas.length > 0
@@ -308,24 +298,31 @@ export default function SchemaDetailsPage() {
   }
 
   const showDeleteSchemaConfirm = name => {
+    let validateFn = null
+
+    const registerValidate = fn => {
+      validateFn = fn
+    }
+
     modal.confirm({
       title: `Are you sure to delete the schema ${name}?`,
       icon: <ExclamationCircleFilled />,
+      content: <ConfirmInput name={name} registerValidate={registerValidate} 
/>,
       okText: 'Delete',
       okType: 'danger',
       cancelText: 'Cancel',
-      onOk: async () => {
+      async onOk() {
+        if (validateFn && !validateFn()) return
+
         await dispatch(deleteSchema({ metalake: currentMetalake, catalog, 
catalogType, schema: name }))
 
-        const [err, res] = await to(
-          dispatch(fetchSchemas({ metalake: currentMetalake, catalog, 
catalogType, parentSchema: schema }))
+        // Fetch subschemas again to update store.subschemas
+        await dispatch(fetchSchemas({ metalake: currentMetalake, catalog, 
catalogType, parentSchema: schema }))
+
+        treeRef.current.onLoadData(
+          { key: 
`{{${currentMetalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}`, 
nodeType: 'schema' },
+          true
         )
-        if (!err && res) {
-          const { schemas = [] } = res.payload || {}
-          const nextSubSchemas = schemas.map(item => ({ ...item, name: 
item.name, key: item.name, title: item.name }))
-          setSubSchemas(nextSubSchemas)
-        }
-        treeRef.current.onLoadData({ key: catalog, nodeType: 'catalog', inUse: 
'true' }, true)
       }
     })
   }
@@ -485,13 +482,8 @@ export default function SchemaDetailsPage() {
       location = catalogData?.provider === 'hive' ? 
table.properties?.['location'] : ''
     }
 
-    let confirmInput = ''
     let validateFn = null
 
-    const setConfirmInput = value => {
-      confirmInput = value
-    }
-
     const registerValidate = fn => {
       validateFn = fn
     }
@@ -500,13 +492,7 @@ export default function SchemaDetailsPage() {
       title: `Are you sure to delete the ${type} ${entity}?`,
       icon: <ExclamationCircleFilled />,
       content: (
-        <ConfirmInput
-          name={entity}
-          setConfirmInput={setConfirmInput}
-          isManaged={isManaged}
-          location={location}
-          registerValidate={registerValidate}
-        />
+        <ConfirmInput name={entity} isManaged={isManaged} location={location} 
registerValidate={registerValidate} />
       ),
       okText: 'Delete',
       okType: 'danger',
@@ -660,7 +646,7 @@ export default function SchemaDetailsPage() {
       showDeleteConfirm: name => showDeleteSchemaConfirm(name),
       handleSetOwner
     })
-  }, [currentMetalake, catalog, catalogType, anthEnable, 
catalogData?.provider])
+  }, [currentMetalake, catalog, catalogType, schema, anthEnable, 
catalogData?.provider])
 
   const { resizableColumns, components, tableWidth } = useAntdColumnResize(() 
=> {
     return { columns, minWidth: 100 }
diff --git a/web-v2/web/src/components/ConfirmInput.js 
b/web-v2/web/src/components/ConfirmInput.js
index 46bbdcf74a..e780ad030d 100644
--- a/web-v2/web/src/components/ConfirmInput.js
+++ b/web-v2/web/src/components/ConfirmInput.js
@@ -93,7 +93,7 @@ const ConfirmInput = forwardRef(function ConfirmInput(props, 
ref) {
         status={getStatus()}
         onChange={e => {
           setValue(e.target.value)
-          setConfirmInput(e.target.value)
+          setConfirmInput?.(e.target.value)
           if (showError) setShowError(false)
         }}
       />
diff --git a/web-v2/web/src/lib/store/metalakes/index.js 
b/web-v2/web/src/lib/store/metalakes/index.js
index 59cc872fd7..2f6cd2c4a5 100644
--- a/web-v2/web/src/lib/store/metalakes/index.js
+++ b/web-v2/web/src/lib/store/metalakes/index.js
@@ -335,7 +335,8 @@ export const setIntoTreeNodeWithFetch = createAsyncThunk(
                 name: schemaName,
                 title: schemaName,
                 tables: [],
-                children: []
+                children: [],
+                isLeaf: reload ? false : undefined
               }
             })
           : []
@@ -451,6 +452,7 @@ export const setIntoTreeNodeWithFetch = createAsyncThunk(
       }
 
       result.data = [...childSchemas, ...entities, ...functions, ...views]
+      result.entities = entities
     }
 
     return result
@@ -946,7 +948,7 @@ export const fetchSchemas = createAsyncThunk(
 
     dispatch(setExpandedNodes([`{{${metalake}}}`, 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}`]))
 
-    return { schemas, page, init }
+    return { schemas, page, init, parentSchema }
   }
 )
 
@@ -990,7 +992,7 @@ export const createSchema = createAsyncThunk(
       children: []
     }
 
-    dispatch(fetchSchemas({ metalake, catalog, catalogType, init: true }))
+    await dispatch(fetchSchemas({ metalake, catalog, catalogType, init: true 
}))
 
     return schemaData
   }
@@ -2327,6 +2329,7 @@ export const appMetalakesSlice = createSlice({
     tableProps: [],
     catalogs: [],
     schemas: [],
+    subschemas: [],
     tables: [],
     functions: [],
     views: [],
@@ -2392,6 +2395,7 @@ export const appMetalakesSlice = createSlice({
       state.tableProps = []
       state.catalogs = []
       state.schemas = []
+      state.subschemas = []
       state.tables = []
       state.functions = []
       state.views = []
@@ -2401,6 +2405,9 @@ export const appMetalakesSlice = createSlice({
       state.models = []
       state.versions = []
     },
+    setSubschemas(state, action) {
+      state.subschemas = action.payload
+    },
     setTableLoading(state, action) {
       state.tableLoading = action.payload
     },
@@ -2706,9 +2713,13 @@ export const appMetalakesSlice = createSlice({
       }
     })
     builder.addCase(setIntoTreeNodeWithFetch.fulfilled, (state, action) => {
-      const { key, data } = action.payload
+      const { key, data, entities } = action.payload
 
       state.metalakeTree = updateTreeData(state.metalakeTree, key, data)
+
+      if (entities && state.selectedNodes.includes(key)) {
+        state.tableData = entities
+      }
     })
     builder.addCase(setIntoTreeNodeWithFetch.rejected, (state, action) => {
       if (!action.error.message.includes('CanceledError')) {
@@ -2816,7 +2827,11 @@ export const appMetalakesSlice = createSlice({
       }
     })
     builder.addCase(fetchSchemas.fulfilled, (state, action) => {
-      state.schemas = action.payload.schemas
+      if (action.payload.parentSchema) {
+        state.subschemas = action.payload.schemas
+      } else {
+        state.schemas = action.payload.schemas
+      }
       if (action.payload.init) {
         state.tableData = action.payload.schemas
       }
diff --git a/web-v2/web/src/lib/utils/index.js 
b/web-v2/web/src/lib/utils/index.js
index e9e9fc0b81..1c847cf344 100644
--- a/web-v2/web/src/lib/utils/index.js
+++ b/web-v2/web/src/lib/utils/index.js
@@ -308,9 +308,11 @@ export function extractPlaceholder(str) {
 export const updateTreeData = (list = [], key, children = []) => {
   return list.map(node => {
     if (node.key === key) {
+      const isLeaf = children?.length === 0
+
       return {
         ...node,
-        isLeaf: children?.length === 0,
+        isLeaf,
         children
       }
     }

Reply via email to