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
}
}