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

jshao 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 7baafec434 [#9696] web-v2(impr): update store data and tree node 
refplace list entity  after update entity (#10054)
7baafec434 is described below

commit 7baafec434ebd5ddb4d54331a540321fd9cff85a
Author: Qian Xia <[email protected]>
AuthorDate: Mon Mar 2 14:37:23 2026 +0800

    [#9696] web-v2(impr): update store data and tree node refplace list entity  
after update entity (#10054)
    
    ### What changes were proposed in this pull request?
    <img width="3110" height="1870" alt="image"
    
src="https://github.com/user-attachments/assets/5cce7867-098a-49b2-951c-03ecf666f834";
    />
    <img width="3452" height="1770" alt="image"
    
src="https://github.com/user-attachments/assets/8011691b-1e29-4568-aaf8-f2aa790f216a";
    />
    
    1. update table only reload tags and policies of the table
    2. improve this situation for catalog/schema/topic/fileset/model
    
    ### Why are the changes needed?
    N/A
    
    Fix: #9696
    
    ### Does this PR introduce _any_ user-facing change?
    N/A
    
    ### How was this patch tested?
    manually
    
    ---------
    
    Co-authored-by: Copilot <[email protected]>
---
 .../catalogs/rightContent/CreateCatalogDialog.js   |   2 +-
 .../catalogs/rightContent/CreateFilesetDialog.js   |   4 +-
 .../app/catalogs/rightContent/CreateTableDialog.js |   2 +-
 .../app/catalogs/rightContent/CreateTopicDialog.js |   6 +-
 .../catalogs/rightContent/RegisterModelDialog.js   |   4 +-
 .../entitiesContent/CatalogDetailsPage.js          |   2 +
 .../rightContent/entitiesContent/CatalogsPage.js   |   2 +-
 .../entitiesContent/SchemaDetailsPage.js           |   1 +
 .../entitiesContent/TopicDetailsPage.js            |   1 +
 web-v2/web/src/lib/store/metalakes/index.js        | 641 ++++++++++++++++++++-
 10 files changed, 644 insertions(+), 21 deletions(-)

diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateCatalogDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateCatalogDialog.js
index c7eeafba5a..b1dab97d56 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateCatalogDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateCatalogDialog.js
@@ -494,7 +494,7 @@ export default function CreateCatalogDialog({ ...props }) {
                       messageVariables={{ label: 'catalog name' }}
                       data-refer='catalog-name-field'
                     >
-                      <Input placeholder={mismatchName} disabled={!init} />
+                      <Input placeholder={mismatchName} disabled={init} />
                     </Form.Item>
                     {providerBase[catalogType === 'model' ? 'model' : 
currentProvider]?.defaultProps
                       ?.filter(p => !isHidden(p))
diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateFilesetDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateFilesetDialog.js
index da357f5ed3..b11893d83a 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateFilesetDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateFilesetDialog.js
@@ -176,13 +176,13 @@ export default function CreateFilesetDialog({ ...props }) 
{
           const reqData = { updates: genUpdates(cacheData, submitData) }
           if (reqData.updates.length) {
             await dispatch(
-              updateFileset({ data: reqData, metalake, catalog, catalogType, 
schema, fileset: cacheData.name })
+              updateFileset({ init, data: reqData, metalake, catalog, 
catalogType, schema, fileset: cacheData.name })
             )
           }
         } else {
           await dispatch(createFileset({ data: submitData, metalake, catalog, 
catalogType, schema }))
         }
-        treeRef.current.onLoadData({ key: `${catalog}/${schema}`, nodeType: 
'schema' })
+        !editFileset && treeRef.current.onLoadData({ key: 
`${catalog}/${schema}`, nodeType: 'schema' })
         setConfirmLoading(false)
         setOpen(false)
       })
diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
index f528acd635..a15bf07b6d 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
@@ -724,7 +724,7 @@ export default function CreateTableDialog({ ...props }) {
           }
 
           if (submitted) {
-            treeRef.current.onLoadData({ key: `${catalog}/${schema}`, 
nodeType: 'schema' })
+            !editTable && treeRef.current.onLoadData({ key: 
`${catalog}/${schema}`, nodeType: 'schema' })
             setOpen(false)
           }
         } catch (error) {
diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateTopicDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateTopicDialog.js
index c9c7fe962f..2c39366087 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateTopicDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateTopicDialog.js
@@ -132,12 +132,14 @@ export default function CreateTopicDialog({ ...props }) {
           // update topic
           const reqData = { updates: genUpdates(cacheData, submitData) }
           if (reqData.updates.length) {
-            await dispatch(updateTopic({ metalake, catalog, catalogType, 
schema, topic: editTopic, data: reqData }))
+            await dispatch(
+              updateTopic({ init, metalake, catalog, catalogType, schema, 
topic: editTopic, data: reqData })
+            )
           }
         } else {
           await dispatch(createTopic({ data: submitData, metalake, catalog, 
schema, catalogType }))
         }
-        init && treeRef.current.onLoadData({ key: `${catalog}/${schema}`, 
nodeType: 'schema' })
+        !editTopic && treeRef.current.onLoadData({ key: 
`${catalog}/${schema}`, nodeType: 'schema' })
         setConfirmLoading(false)
         setOpen(false)
       })
diff --git a/web-v2/web/src/app/catalogs/rightContent/RegisterModelDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/RegisterModelDialog.js
index 5c6994d22b..a001d36d02 100644
--- a/web-v2/web/src/app/catalogs/rightContent/RegisterModelDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/RegisterModelDialog.js
@@ -136,7 +136,9 @@ export default function RegisterModelDialog({ ...props }) {
           // update model
           const reqData = { updates: genUpdates(cacheData, submitData) }
           if (reqData.updates.length) {
-            await dispatch(updateModel({ metalake, catalog, catalogType, 
schema, model: editModel, data: reqData }))
+            await dispatch(
+              updateModel({ init, metalake, catalog, catalogType, schema, 
model: editModel, data: reqData })
+            )
           }
         } else {
           await dispatch(registerModel({ data: submitData, metalake, catalog, 
schema, catalogType }))
diff --git 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogDetailsPage.js
 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogDetailsPage.js
index f59bf91fa8..ca1dd8d71b 100644
--- 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogDetailsPage.js
+++ 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogDetailsPage.js
@@ -502,6 +502,7 @@ export default function CatalogDetailsPage() {
               
locationProviders={store.activatedDetails?.properties?.['filesystem-providers']?.split(',')
 || []}
               
catalogBackend={store.activatedDetails?.properties?.['catalog-backend']}
               editSchema={editSchema}
+              init={false}
             />
           )}
         </>
@@ -520,6 +521,7 @@ export default function CatalogDetailsPage() {
           editCatalog={catalog}
           catalogType={catalogType}
           systemConfig={systemConfig}
+          init={true}
         />
       )}
       {openOwner && (
diff --git 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogsPage.js 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogsPage.js
index 7c733648d6..d094ae7544 100644
--- a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogsPage.js
+++ b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/CatalogsPage.js
@@ -385,7 +385,7 @@ export default function CatalogsPage() {
           metalake={currentMetalake}
           catalogType={catalogType}
           editCatalog={editCatalog}
-          init={true}
+          init={false}
         />
       )}
       {openOwner && (
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 38555281d6..8d8168e78f 100644
--- 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js
+++ 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/SchemaDetailsPage.js
@@ -645,6 +645,7 @@ export default function SchemaDetailsPage() {
           provider={catalogData?.provider}
           
locationProviders={catalogData?.properties?.['filesystem-providers']?.split(',')
 || []}
           editSchema={schema}
+          init={true}
         />
       )}
       {openOwner && (
diff --git 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/TopicDetailsPage.js 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/TopicDetailsPage.js
index eb97f93729..140b2cf048 100644
--- 
a/web-v2/web/src/app/catalogs/rightContent/entitiesContent/TopicDetailsPage.js
+++ 
b/web-v2/web/src/app/catalogs/rightContent/entitiesContent/TopicDetailsPage.js
@@ -194,6 +194,7 @@ export default function TopicDetailsPage({ ...props }) {
           catalog={catalog}
           schema={schema}
           editTopic={topic}
+          init={true}
         />
       )}
       {openOwner && (
diff --git a/web-v2/web/src/lib/store/metalakes/index.js 
b/web-v2/web/src/lib/store/metalakes/index.js
index 4eeba36c57..d0f2c318f1 100644
--- a/web-v2/web/src/lib/store/metalakes/index.js
+++ b/web-v2/web/src/lib/store/metalakes/index.js
@@ -79,6 +79,16 @@ import {
 } from '@/lib/api/models'
 import { getFunctionsApi } from '@/lib/api/functions'
 
+const remapExpandedAndLoadedNodes = ({ getState, mapNode }) => {
+  const expandedNodes = getState().metalakes.expandedNodes.map(mapNode)
+  const loadedNodes = getState().metalakes.loadedNodes.map(mapNode)
+
+  return {
+    expanded: expandedNodes,
+    loaded: loadedNodes
+  }
+}
+
 export const fetchMetalakes = createAsyncThunk('appMetalakes/fetchMetalakes', 
async (params, { getState }) => {
   const [err, res] = await to(getMetalakesApi())
 
@@ -652,15 +662,94 @@ export const testCatalogConnection = createAsyncThunk(
 
 export const updateCatalog = createAsyncThunk(
   'appMetalakes/updateCatalog',
-  async ({ init, metalake, catalog, data }, { dispatch }) => {
+  async ({ init, metalake, catalog, data }, { getState, dispatch }) => {
     const [err, res] = await to(updateCatalogApi({ metalake, catalog, data }))
     if (err || !res) {
       return { err: true }
     }
     if (init) {
-      dispatch(fetchCatalogs({ metalake, update: { catalog, newCatalog: 
res.catalog }, init }))
+      dispatch(getCatalogDetails({ init, metalake, catalog }))
     } else {
-      dispatch(getCatalogDetails({ init: true, metalake, catalog }))
+      dispatch(updateCatalogInStore({ metalake, catalog, newCatalog: 
res.catalog }))
+
+      if (catalog !== res.catalog.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name === catalog) {
+            const schemas = catalogItem.children
+              ? catalogItem.children.map(schema => {
+                  const tables = schema.children
+                    ? schema.children.map(table => {
+                        return {
+                          ...table,
+                          id: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}{{${schema.name}}}{{${table.name}}}`,
+                          key: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}{{${schema.name}}}{{${table.name}}}`,
+                          path: `?${new URLSearchParams({
+                            metalake,
+                            catalog: res.catalog.name,
+                            catalogType: res.catalog.type,
+                            schema: schema.name,
+                            table: table.name
+                          }).toString()}`
+                        }
+                      })
+                    : []
+
+                  return {
+                    ...schema,
+                    id: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}{{${schema.name}}}`,
+                    key: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}{{${schema.name}}}`,
+                    path: `?${new URLSearchParams({
+                      metalake,
+                      catalog: res.catalog.name,
+                      catalogType: res.catalog.type,
+                      schema: schema.name
+                    }).toString()}`,
+                    tables: tables,
+                    children: tables
+                  }
+                })
+              : []
+
+            return {
+              ...catalogItem,
+              id: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}`,
+              key: 
`{{${metalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}`,
+              path: `?${new URLSearchParams({
+                metalake,
+                catalog: res.catalog.name,
+                catalogType: res.catalog.type
+              }).toString()}`,
+              catalogType: res.catalog.type,
+              provider: res.catalog.provider,
+              name: res.catalog.name,
+              title: res.catalog.name,
+              schemas: schemas,
+              children: schemas
+            }
+          }
+
+          return { ...catalogItem }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, entity] = extractPlaceholder(node)
+            if (currentCatalog !== catalog) {
+              return node
+            }
+
+            return 
`{{${currentMetalake}}}{{${res.catalog.name}}}{{${res.catalog.type}}}${
+              currentSchema ? `{{${currentSchema}}}` : ''
+            }${entity ? `{{${entity}}}` : ''}`
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
     }
 
     return res.catalog
@@ -806,7 +895,7 @@ export const createSchema = createAsyncThunk(
 
 export const updateSchema = createAsyncThunk(
   'appMetalakes/updateSchema',
-  async ({ init, metalake, catalog, catalogType, schema, data }, { dispatch }) 
=> {
+  async ({ init, metalake, catalog, catalogType, schema, data }, { getState, 
dispatch }) => {
     const [err, res] = await to(updateSchemaApi({ metalake, catalog, schema, 
data }))
     if (err || !res) {
       return { err: true }
@@ -814,7 +903,73 @@ export const updateSchema = createAsyncThunk(
     if (init) {
       dispatch(getSchemaDetails({ init, metalake, catalog, schema }))
     } else {
-      dispatch(fetchSchemas({ metalake, catalog, catalogType, init: true }))
+      dispatch(updateSchemaInStore({ metalake, catalog, catalogType, schema, 
newSchema: res.schema }))
+
+      if (schema !== res.schema.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name !== catalog) return { ...catalogItem }
+
+          const schemas = catalogItem.children
+            ? catalogItem.children.map(schemaItem => {
+                if (schemaItem.name !== schema) return { ...schemaItem }
+
+                const tables = schemaItem.children
+                  ? schemaItem.children.map(table => {
+                      return {
+                        ...table,
+                        id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${res.schema.name}}}{{${table.name}}}`,
+                        key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${res.schema.name}}}{{${table.name}}}`,
+                        path: `?${new URLSearchParams({
+                          metalake,
+                          catalog,
+                          catalogType,
+                          schema: res.schema.name,
+                          table: table.name
+                        }).toString()}`
+                      }
+                    })
+                  : []
+
+                return {
+                  ...schemaItem,
+                  ...res.schema,
+                  id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${res.schema.name}}}`,
+                  key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${res.schema.name}}}`,
+                  path: `?${new URLSearchParams({ metalake, catalog, 
catalogType, schema: res.schema.name }).toString()}`,
+                  name: res.schema.name,
+                  title: res.schema.name,
+                  tables: tables,
+                  children: tables
+                }
+              })
+            : []
+
+          return {
+            ...catalogItem,
+            schemas: schemas,
+            children: schemas
+          }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, table] = extractPlaceholder(node)
+            if (currentCatalog === catalog && currentType === catalogType && 
currentSchema === schema) {
+              return 
`{{${currentMetalake}}}{{${currentCatalog}}}{{${currentType}}}{{${res.schema.name}}}${
+                table ? `{{${table}}}` : ''
+              }`
+            }
+
+            return node
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
     }
 
     return res.schema
@@ -1051,7 +1206,7 @@ export const createTable = createAsyncThunk(
 
 export const updateTable = createAsyncThunk(
   'appMetalakes/updateTable',
-  async ({ init, metalake, catalog, catalogType, schema, table, data }, { 
dispatch }) => {
+  async ({ init, metalake, catalog, catalogType, schema, table, data }, { 
getState, dispatch }) => {
     const [err, res] = await to(updateTableApi({ metalake, catalog, schema, 
table, data }))
     if (err || !res) {
       return { err: true }
@@ -1060,7 +1215,75 @@ export const updateTable = createAsyncThunk(
     if (init) {
       await dispatch(getTableDetails({ init, metalake, catalog, catalogType, 
schema, table }))
     } else {
-      await dispatch(fetchTables({ metalake, catalog, catalogType, schema, 
page: 'schemas', init: true }))
+      dispatch(updateTableInStore({ metalake, catalog, catalogType, schema, 
table, newTable: res.table }))
+
+      if (table !== res.table.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name !== catalog) return { ...catalogItem }
+
+          const schemas = catalogItem.children
+            ? catalogItem.children.map(schemaItem => {
+                if (schemaItem.name !== schema) return { ...schemaItem }
+
+                const tables = schemaItem.children
+                  ? schemaItem.children.map(tableItem => {
+                      if (tableItem.name !== table) return { ...tableItem }
+
+                      return {
+                        ...tableItem,
+                        ...res.table,
+                        id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.table.name}}}`,
+                        key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.table.name}}}`,
+                        path: `?${new URLSearchParams({
+                          metalake,
+                          catalog,
+                          catalogType,
+                          schema,
+                          table: res.table.name
+                        }).toString()}`,
+                        name: res.table.name,
+                        title: res.table.name
+                      }
+                    })
+                  : []
+
+                return {
+                  ...schemaItem,
+                  tables: tables,
+                  children: tables
+                }
+              })
+            : []
+
+          return {
+            ...catalogItem,
+            schemas: schemas,
+            children: schemas
+          }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, currentTable] = extractPlaceholder(node)
+            if (
+              currentCatalog === catalog &&
+              currentType === catalogType &&
+              currentSchema === schema &&
+              currentTable === table
+            ) {
+              return 
`{{${currentMetalake}}}{{${currentCatalog}}}{{${currentType}}}{{${currentSchema}}}{{${res.table.name}}}`
+            }
+
+            return node
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
     }
 
     return res.table
@@ -1206,12 +1429,85 @@ export const createFileset = createAsyncThunk(
 
 export const updateFileset = createAsyncThunk(
   'appMetalakes/updateFileset',
-  async ({ metalake, catalog, catalogType, schema, fileset, data }, { dispatch 
}) => {
+  async ({ init, metalake, catalog, catalogType, schema, fileset, data }, { 
getState, dispatch }) => {
     const [err, res] = await to(updateFilesetApi({ metalake, catalog, schema, 
fileset, data }))
     if (err || !res) {
       return { err: true }
     }
-    await dispatch(fetchFilesets({ metalake, catalog, catalogType, schema, 
init: true }))
+
+    if (init) {
+      await dispatch(getFilesetDetails({ init, metalake, catalog, schema, 
fileset }))
+    } else {
+      dispatch(updateFilesetInStore({ metalake, catalog, catalogType, schema, 
fileset, newFileset: res.fileset }))
+
+      if (fileset !== res.fileset.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name !== catalog) return { ...catalogItem }
+
+          const schemas = catalogItem.children
+            ? catalogItem.children.map(schemaItem => {
+                if (schemaItem.name !== schema) return { ...schemaItem }
+
+                const filesets = schemaItem.children
+                  ? schemaItem.children.map(filesetItem => {
+                      if (filesetItem.name !== fileset) return { 
...filesetItem }
+
+                      return {
+                        ...filesetItem,
+                        ...res.fileset,
+                        id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.fileset.name}}}`,
+                        key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.fileset.name}}}`,
+                        path: `?${new URLSearchParams({
+                          metalake,
+                          catalog,
+                          catalogType,
+                          schema,
+                          fileset: res.fileset.name
+                        }).toString()}`,
+                        name: res.fileset.name,
+                        title: res.fileset.name,
+                        isLeaf: true
+                      }
+                    })
+                  : []
+
+                return {
+                  ...schemaItem,
+                  children: filesets
+                }
+              })
+            : []
+
+          return {
+            ...catalogItem,
+            children: schemas
+          }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, currentFileset] =
+              extractPlaceholder(node)
+            if (
+              currentCatalog === catalog &&
+              currentType === catalogType &&
+              currentSchema === schema &&
+              currentFileset === fileset
+            ) {
+              return 
`{{${currentMetalake}}}{{${currentCatalog}}}{{${currentType}}}{{${currentSchema}}}{{${res.fileset.name}}}`
+            }
+
+            return node
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
+    }
 
     return res.fileset
   }
@@ -1372,12 +1668,84 @@ export const createTopic = createAsyncThunk(
 
 export const updateTopic = createAsyncThunk(
   'appMetalakes/updateTopic',
-  async ({ metalake, catalog, catalogType, schema, topic, data }, { dispatch 
}) => {
+  async ({ init, metalake, catalog, catalogType, schema, topic, data }, { 
getState, dispatch }) => {
     const [err, res] = await to(updateTopicApi({ metalake, catalog, schema, 
topic, data }))
     if (err || !res) {
       return { err: true }
     }
-    await dispatch(fetchTopics({ metalake, catalog, catalogType, schema, init: 
true }))
+
+    if (init) {
+      await dispatch(getTopicDetails({ init, metalake, catalog, schema, topic 
}))
+    } else {
+      dispatch(updateTopicInStore({ metalake, catalog, catalogType, schema, 
topic, newTopic: res.topic }))
+
+      if (topic !== res.topic.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name !== catalog) return { ...catalogItem }
+
+          const schemas = catalogItem.children
+            ? catalogItem.children.map(schemaItem => {
+                if (schemaItem.name !== schema) return { ...schemaItem }
+
+                const topics = schemaItem.children
+                  ? schemaItem.children.map(topicItem => {
+                      if (topicItem.name !== topic) return { ...topicItem }
+
+                      return {
+                        ...topicItem,
+                        ...res.topic,
+                        id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.topic.name}}}`,
+                        key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.topic.name}}}`,
+                        path: `?${new URLSearchParams({
+                          metalake,
+                          catalog,
+                          catalogType,
+                          schema,
+                          topic: res.topic.name
+                        }).toString()}`,
+                        name: res.topic.name,
+                        title: res.topic.name,
+                        isLeaf: true
+                      }
+                    })
+                  : []
+
+                return {
+                  ...schemaItem,
+                  children: topics
+                }
+              })
+            : []
+
+          return {
+            ...catalogItem,
+            children: schemas
+          }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, currentTopic] = extractPlaceholder(node)
+            if (
+              currentCatalog === catalog &&
+              currentType === catalogType &&
+              currentSchema === schema &&
+              currentTopic === topic
+            ) {
+              return 
`{{${currentMetalake}}}{{${currentCatalog}}}{{${currentType}}}{{${currentSchema}}}{{${res.topic.name}}}`
+            }
+
+            return node
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
+    }
 
     return res.topic
   }
@@ -1503,12 +1871,84 @@ export const registerModel = createAsyncThunk(
 
 export const updateModel = createAsyncThunk(
   'appMetalakes/updateModel',
-  async ({ metalake, catalog, catalogType, schema, model, data }, { dispatch 
}) => {
+  async ({ init, metalake, catalog, catalogType, schema, model, data }, { 
getState, dispatch }) => {
     const [err, res] = await to(updateModelApi({ metalake, catalog, schema, 
model, data }))
     if (err || !res) {
       return { err: true }
     }
-    await dispatch(fetchModels({ metalake, catalog, catalogType, schema, init: 
true }))
+
+    if (init) {
+      await dispatch(getModelDetails({ init, metalake, catalog, schema, model 
}))
+    } else {
+      dispatch(updateModelInStore({ metalake, catalog, catalogType, schema, 
model, newModel: res.model }))
+
+      if (model !== res.model.name) {
+        const tree = getState().metalakes.metalakeTree.map(catalogItem => {
+          if (catalogItem.name !== catalog) return { ...catalogItem }
+
+          const schemas = catalogItem.children
+            ? catalogItem.children.map(schemaItem => {
+                if (schemaItem.name !== schema) return { ...schemaItem }
+
+                const models = schemaItem.children
+                  ? schemaItem.children.map(modelItem => {
+                      if (modelItem.name !== model) return { ...modelItem }
+
+                      return {
+                        ...modelItem,
+                        ...res.model,
+                        id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.model.name}}}`,
+                        key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${res.model.name}}}`,
+                        path: `?${new URLSearchParams({
+                          metalake,
+                          catalog,
+                          catalogType,
+                          schema,
+                          model: res.model.name
+                        }).toString()}`,
+                        name: res.model.name,
+                        title: res.model.name,
+                        isLeaf: true
+                      }
+                    })
+                  : []
+
+                return {
+                  ...schemaItem,
+                  children: models
+                }
+              })
+            : []
+
+          return {
+            ...catalogItem,
+            children: schemas
+          }
+        })
+
+        dispatch(setMetalakeTree(tree))
+
+        const { expanded, loaded } = remapExpandedAndLoadedNodes({
+          getState,
+          mapNode: node => {
+            const [currentMetalake, currentCatalog, currentType, 
currentSchema, currentModel] = extractPlaceholder(node)
+            if (
+              currentCatalog === catalog &&
+              currentType === catalogType &&
+              currentSchema === schema &&
+              currentModel === model
+            ) {
+              return 
`{{${currentMetalake}}}{{${currentCatalog}}}{{${currentType}}}{{${currentSchema}}}{{${res.model.name}}}`
+            }
+
+            return node
+          }
+        })
+
+        dispatch(setExpanded(expanded))
+        dispatch(setLoadedNodes(loaded))
+      }
+    }
 
     return res.model
   }
@@ -1766,6 +2206,175 @@ export const appMetalakesSlice = createSlice({
       const { key, data } = action.payload
       state.metalakeTree = updateTreeData(state.metalakeTree, key, data)
     },
+    updateCatalogInStore(state, action) {
+      const { metalake, catalog, newCatalog } = action.payload
+
+      const updateCatalogItem = item => {
+        if (!item || item.name !== catalog) return item
+        const schemas = item.children || item.schemas || []
+
+        return {
+          ...item,
+          ...newCatalog,
+          node: 'catalog',
+          id: `{{${metalake}}}{{${newCatalog.name}}}{{${newCatalog.type}}}`,
+          key: `{{${metalake}}}{{${newCatalog.name}}}{{${newCatalog.type}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog: newCatalog.name,
+            catalogType: newCatalog.type
+          }).toString()}`,
+          catalogType: newCatalog.type,
+          provider: newCatalog.provider,
+          name: newCatalog.name,
+          title: newCatalog.name,
+          namespace: [metalake],
+          schemas: schemas,
+          children: schemas
+        }
+      }
+
+      state.catalogs = state.catalogs.map(updateCatalogItem)
+      state.tableData = state.tableData.map(updateCatalogItem)
+    },
+    updateSchemaInStore(state, action) {
+      const { metalake, catalog, catalogType, schema, newSchema } = 
action.payload
+
+      const updateSchemaItem = item => {
+        if (!item || item.name !== schema) return item
+
+        return {
+          ...item,
+          ...newSchema,
+          node: 'schema',
+          id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${newSchema.name}}}`,
+          key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${newSchema.name}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog,
+            catalogType,
+            schema: newSchema.name
+          }).toString()}`,
+          name: newSchema.name,
+          title: newSchema.name
+        }
+      }
+
+      state.schemas = state.schemas.map(updateSchemaItem)
+      state.tableData = state.tableData.map(updateSchemaItem)
+    },
+    updateTableInStore(state, action) {
+      const { metalake, catalog, catalogType, schema, table, newTable } = 
action.payload
+
+      const updateTableItem = item => {
+        if (!item || item.name !== table) return item
+
+        return {
+          ...item,
+          ...newTable,
+          node: 'table',
+          id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newTable.name}}}`,
+          key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newTable.name}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog,
+            catalogType,
+            schema,
+            table: newTable.name
+          }).toString()}`,
+          name: newTable.name,
+          title: newTable.name,
+          isLeaf: true
+        }
+      }
+
+      state.tables = state.tables.map(updateTableItem)
+      state.tableData = state.tableData.map(updateTableItem)
+    },
+    updateTopicInStore(state, action) {
+      const { metalake, catalog, catalogType, schema, topic, newTopic } = 
action.payload
+
+      const updateTopicItem = item => {
+        if (!item || item.name !== topic) return item
+
+        return {
+          ...item,
+          ...newTopic,
+          node: 'topic',
+          id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newTopic.name}}}`,
+          key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newTopic.name}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog,
+            catalogType,
+            schema,
+            topic: newTopic.name
+          }).toString()}`,
+          name: newTopic.name,
+          title: newTopic.name,
+          isLeaf: true
+        }
+      }
+
+      state.topics = state.topics.map(updateTopicItem)
+      state.tableData = state.tableData.map(updateTopicItem)
+    },
+    updateFilesetInStore(state, action) {
+      const { metalake, catalog, catalogType, schema, fileset, newFileset } = 
action.payload
+
+      const updateFilesetItem = item => {
+        if (!item || item.name !== fileset) return item
+
+        return {
+          ...item,
+          ...newFileset,
+          node: 'fileset',
+          id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newFileset.name}}}`,
+          key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newFileset.name}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog,
+            catalogType,
+            schema,
+            fileset: newFileset.name
+          }).toString()}`,
+          name: newFileset.name,
+          title: newFileset.name,
+          isLeaf: true
+        }
+      }
+
+      state.filesets = state.filesets.map(updateFilesetItem)
+      state.tableData = state.tableData.map(updateFilesetItem)
+    },
+    updateModelInStore(state, action) {
+      const { metalake, catalog, catalogType, schema, model, newModel } = 
action.payload
+
+      const updateModelItem = item => {
+        if (!item || item.name !== model) return item
+
+        return {
+          ...item,
+          ...newModel,
+          node: 'model',
+          id: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newModel.name}}}`,
+          key: 
`{{${metalake}}}{{${catalog}}}{{${catalogType}}}{{${schema}}}{{${newModel.name}}}`,
+          path: `?${new URLSearchParams({
+            metalake,
+            catalog,
+            catalogType,
+            schema,
+            model: newModel.name
+          }).toString()}`,
+          name: newModel.name,
+          title: newModel.name,
+          isLeaf: true
+        }
+      }
+
+      state.models = state.models.map(updateModelItem)
+      state.tableData = state.tableData.map(updateModelItem)
+    },
     updateCatalogInUse(state, action) {
       const { catalog, isInUse } = action.payload
       const inUseValue = isInUse ? 'true' : 'false'
@@ -2240,6 +2849,12 @@ export const {
   setExpanded,
   setExpandedNodes,
   addCatalogToTree,
+  updateCatalogInStore,
+  updateSchemaInStore,
+  updateTableInStore,
+  updateTopicInStore,
+  updateFilesetInStore,
+  updateModelInStore,
   setCatalogInUse,
   updateCatalogInUse,
   setMetalakeInUse,


Reply via email to