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

jshao pushed a commit to branch branch-0.7
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-0.7 by this push:
     new 3ce16f553 [#5206] UI (metalake, catalog): Web UI add disable/enable 
metalake/catalog button (#5300)
3ce16f553 is described below

commit 3ce16f5539e82779a3cf5fb76c21ec8058cdaf91
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Oct 28 15:25:14 2024 +0800

    [#5206] UI (metalake, catalog): Web UI add disable/enable metalake/catalog 
button (#5300)
    
    ### What changes were proposed in this pull request?
    Web UI add disable/enable metalake/catalog button
    <img width="1380" alt="image"
    
src="https://github.com/user-attachments/assets/00bd7f4c-dc7a-4bbd-83be-5ce998ce5208";>
    <img width="654" alt="image"
    
src="https://github.com/user-attachments/assets/b8d5c20f-b116-444c-8468-d0c4fcb872c2";>
    <img width="544" alt="image"
    
src="https://github.com/user-attachments/assets/95069223-533b-4ad5-af24-53f44c307a5f";>
    <img width="1088" alt="image"
    
src="https://github.com/user-attachments/assets/61f67f28-8d43-4c1b-8a95-31ad90dafc42";>
    <img width="716" alt="image"
    
src="https://github.com/user-attachments/assets/f600d20e-34ba-426d-810b-53d7af6ee2f0";>
    <img width="566" alt="image"
    
src="https://github.com/user-attachments/assets/95b4bd54-4de6-43fe-b198-6e79a8547fa5";>
    
    
    ### Why are the changes needed?
    Fix: #5206
    
    ### Does this PR introduce _any_ user-facing change?
    N/A
    
    ### How was this patch tested?
    manually
    
    Co-authored-by: Qian Xia <[email protected]>
---
 .../integration/test/web/ui/CatalogsPageTest.java  |  1 +
 .../integration/test/web/ui/MetalakePageTest.java  |  1 +
 .../test/web/ui/pages/CatalogsPage.java            |  9 +++
 .../test/web/ui/pages/MetalakePage.java            |  9 +++
 web/web/src/app/metalakes/CreateMetalakeDialog.js  | 16 +++--
 web/web/src/app/metalakes/TableBody.js             | 72 ++++++++++++++-------
 web/web/src/app/metalakes/metalake/MetalakeTree.js |  6 ++
 .../metalake/rightContent/CreateCatalogDialog.js   |  8 ++-
 .../tabsContent/tableView/TableView.js             | 75 +++++++++++++++-------
 web/web/src/components/ConfirmDeleteDialog.js      | 15 +++--
 web/web/src/lib/api/catalogs/index.js              | 12 +++-
 web/web/src/lib/api/metalakes/index.js             | 12 +++-
 web/web/src/lib/store/metalakes/index.js           | 31 +++++++++
 web/web/src/lib/utils/axios/Axios.js               | 10 +++
 14 files changed, 218 insertions(+), 59 deletions(-)

diff --git 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/CatalogsPageTest.java
 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/CatalogsPageTest.java
index 31e50e657..0b140a122 100644
--- 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/CatalogsPageTest.java
+++ 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/CatalogsPageTest.java
@@ -269,6 +269,7 @@ public class CatalogsPageTest extends BaseWebIT {
     catalogsPage.setCatalogFixedProp("metastore.uris", hiveMetastoreUri);
     clickAndWait(catalogsPage.handleSubmitCatalogBtn);
     // delete catalog
+    catalogsPage.clickInUseSwitch(DEFAULT_CATALOG_NAME);
     catalogsPage.clickDeleteCatalogBtn(DEFAULT_CATALOG_NAME);
     clickAndWait(catalogsPage.confirmDeleteBtn);
     Assertions.assertTrue(catalogsPage.verifyEmptyTableData());
diff --git 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/MetalakePageTest.java
 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/MetalakePageTest.java
index fc27dc08b..936179273 100644
--- 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/MetalakePageTest.java
+++ 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/MetalakePageTest.java
@@ -91,6 +91,7 @@ public class MetalakePageTest extends BaseWebIT {
   @Test
   @Order(4)
   public void testDeleteMetalake() {
+    metalakePage.clickInUseSwitch(EDITED_METALAKE_NAME);
     metalakePage.clickDeleteMetalakeBtn(EDITED_METALAKE_NAME);
     metalakePage.confirmDeleteBtn.click();
     Assertions.assertTrue(metalakePage.verifyEmptyMetalake());
diff --git 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/CatalogsPage.java
 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/CatalogsPage.java
index b397c26a7..43a2dd5ba 100644
--- 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/CatalogsPage.java
+++ 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/CatalogsPage.java
@@ -208,6 +208,15 @@ public class CatalogsPage extends BaseWebIT {
     }
   }
 
+  public void clickInUseSwitch(String name) {
+    try {
+      String xpath = "//*[@data-refer='catalog-in-use-" + name + "']";
+      clickAndWait(By.xpath(xpath));
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+    }
+  }
+
   public void clickDeleteCatalogBtn(String name) {
     try {
       String xpath = "//button[@data-refer='delete-entity-" + name + "']";
diff --git 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/MetalakePage.java
 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/MetalakePage.java
index 419589f5a..f2810ab07 100644
--- 
a/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/MetalakePage.java
+++ 
b/web/integration-test/src/test/java/org/apache/gravitino/integration/test/web/ui/pages/MetalakePage.java
@@ -148,6 +148,15 @@ public class MetalakePage extends BaseWebIT {
     queryMetalakeInput.clear();
   }
 
+  public void clickInUseSwitch(String name) {
+    try {
+      String xpath = "//*[@data-refer='metalake-in-use-" + name + "']";
+      clickAndWait(By.xpath(xpath));
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+    }
+  }
+
   public void clickDeleteMetalakeBtn(String name) {
     try {
       String xpath = "//button[@data-refer='delete-metalake-" + name + "']";
diff --git a/web/web/src/app/metalakes/CreateMetalakeDialog.js 
b/web/web/src/app/metalakes/CreateMetalakeDialog.js
index 9dc50df5f..8b8daaadb 100644
--- a/web/web/src/app/metalakes/CreateMetalakeDialog.js
+++ b/web/web/src/app/metalakes/CreateMetalakeDialog.js
@@ -287,6 +287,7 @@ const CreateMetalakeDialog = props => {
                           name='key'
                           label='Key'
                           value={item.key}
+                          disabled={item.key === 'in-use' && type === 'update'}
                           onChange={event => handleFormChange(index, event)}
                           error={item.hasDuplicateKey}
                           data-refer={`add-props-key-${index}`}
@@ -296,14 +297,19 @@ const CreateMetalakeDialog = props => {
                           name='value'
                           label='Value'
                           value={item.value}
+                          disabled={item.key === 'in-use' && type === 'update'}
                           onChange={event => handleFormChange(index, event)}
                           data-refer={`add-props-value-${index}`}
                         />
-                        <Box className={'twc-min-w-[40px]'}>
-                          <IconButton onClick={() => removeFields(index)}>
-                            <Icon icon='mdi:minus-circle-outline' />
-                          </IconButton>
-                        </Box>
+                        {!(item.key === 'in-use' && type === 'update') ? (
+                          <Box className={'twc-min-w-[40px]'}>
+                            <IconButton onClick={() => removeFields(index)}>
+                              <Icon icon='mdi:minus-circle-outline' />
+                            </IconButton>
+                          </Box>
+                        ) : (
+                          <Box sx={{ minWidth: 40 }}></Box>
+                        )}
                       </Box>
                       {item.hasDuplicateKey && (
                         <FormHelperText className={'twc-text-error-main'}>Key 
already exists</FormHelperText>
diff --git a/web/web/src/app/metalakes/TableBody.js 
b/web/web/src/app/metalakes/TableBody.js
index 943e2c0b4..da5ad36c5 100644
--- a/web/web/src/app/metalakes/TableBody.js
+++ b/web/web/src/app/metalakes/TableBody.js
@@ -21,7 +21,7 @@ import { useState, useEffect, Fragment } from 'react'
 
 import Link from 'next/link'
 
-import { Box, Typography, Portal, Tooltip, IconButton } from '@mui/material'
+import { Box, Typography, Portal, Tooltip, IconButton, Switch } from 
'@mui/material'
 import { DataGrid, GridToolbar } from '@mui/x-data-grid'
 import {
   VisibilityOutlined as ViewIcon,
@@ -31,7 +31,15 @@ import {
 
 import { formatToDateTime } from '@/lib/utils/date'
 import { useAppDispatch, useAppSelector } from '@/lib/hooks/useStore'
-import { fetchMetalakes, setFilteredMetalakes, deleteMetalake, resetTree } 
from '@/lib/store/metalakes'
+import {
+  fetchMetalakes,
+  setFilteredMetalakes,
+  deleteMetalake,
+  resetTree,
+  setMetalakeInUse
+} from '@/lib/store/metalakes'
+import { switchInUseApi } from '@/lib/api/metalakes'
+import { to } from '@/lib/utils'
 import ConfirmDeleteDialog from '@/components/ConfirmDeleteDialog'
 
 const TableBody = props => {
@@ -46,12 +54,12 @@ const TableBody = props => {
 
   const handleDeleteMetalake = name => () => {
     setOpenConfirmDelete(true)
-    setConfirmCacheData(name)
+    setConfirmCacheData({ name, type: 'metalake' })
   }
 
   const handleConfirmDeleteSubmit = () => {
     if (confirmCacheData) {
-      dispatch(deleteMetalake(confirmCacheData))
+      dispatch(deleteMetalake(confirmCacheData.name))
       setOpenConfirmDelete(false)
     }
   }
@@ -76,6 +84,14 @@ const TableBody = props => {
     dispatch(resetTree())
   }
 
+  const handleChangeInUse = async (name, isInUse) => {
+    const [err, res] = await to(switchInUseApi({ name, isInUse }))
+    if (err || !res) {
+      throw new Error(err)
+    }
+    dispatch(setMetalakeInUse({ name, isInUse }))
+  }
+
   useEffect(() => {
     dispatch(fetchMetalakes())
   }, [dispatch])
@@ -109,24 +125,36 @@ const TableBody = props => {
         return (
           <Box sx={{ display: 'flex', alignItems: 'center' }}>
             <Tooltip title={row.comment} placement='right'>
-              <Typography
-                noWrap
-                component={Link}
-                href={`/metalakes?metalake=${name}`}
-                onClick={() => handleClickLink()}
-                sx={{
-                  fontWeight: 500,
-                  color: 'primary.main',
-                  textDecoration: 'none',
-                  maxWidth: 240,
-                  overflow: 'hidden',
-                  textOverflow: 'ellipsis',
-                  '&:hover': { color: 'primary.main', textDecoration: 
'underline' }
-                }}
-                data-refer={`metalake-link-${name}`}
-              >
-                {name}
-              </Typography>
+              {row.properties['in-use'] === 'true' ? (
+                <Typography
+                  noWrap
+                  component={Link}
+                  href={`/metalakes?metalake=${name}`}
+                  onClick={() => handleClickLink()}
+                  sx={{
+                    fontWeight: 500,
+                    color: 'primary.main',
+                    textDecoration: 'none',
+                    maxWidth: 240,
+                    overflow: 'hidden',
+                    textOverflow: 'ellipsis',
+                    '&:hover': { color: 'primary.main', textDecoration: 
'underline' }
+                  }}
+                  data-refer={`metalake-link-${name}`}
+                >
+                  {name}
+                </Typography>
+              ) : (
+                <Typography>{name}</Typography>
+              )}
+            </Tooltip>
+            <Tooltip title={row.properties['in-use'] === 'true' ? 'In-use' : 
'Not In-use'} placement='right'>
+              <Switch
+                data-refer={`metalake-in-use-${name}`}
+                checked={row.properties['in-use'] === 'true'}
+                onChange={(e, value) => handleChangeInUse(name, value)}
+                size='small'
+              />
             </Tooltip>
           </Box>
         )
diff --git a/web/web/src/app/metalakes/metalake/MetalakeTree.js 
b/web/web/src/app/metalakes/metalake/MetalakeTree.js
index 74065f933..9f17480df 100644
--- a/web/web/src/app/metalakes/metalake/MetalakeTree.js
+++ b/web/web/src/app/metalakes/metalake/MetalakeTree.js
@@ -86,6 +86,7 @@ const MetalakeTree = props => {
 
   const handleClickIcon = (e, nodeProps) => {
     e.stopPropagation()
+    if (nodeProps.data.inUse === 'false') return
 
     switch (nodeProps.data.node) {
       case 'table': {
@@ -118,6 +119,7 @@ const MetalakeTree = props => {
   }
 
   const onMouseEnter = (e, nodeProps) => {
+    if (nodeProps.data.inUse === 'false') return
     if (nodeProps.data.node === 'table') {
       if (store.selectedNodes.includes(nodeProps.data.key)) {
         setIsHover(nodeProps.data.key)
@@ -128,10 +130,12 @@ const MetalakeTree = props => {
   }
 
   const onMouseLeave = (e, nodeProps) => {
+    if (nodeProps.data.inUse === 'false') return
     setIsHover(null)
   }
 
   const onLoadData = node => {
+    if (node.inUse === 'false') return new Promise(resolve => resolve())
     const { key, children } = node
 
     dispatch(setLoadedNodes([...store.loadedNodes, key]))
@@ -150,6 +154,7 @@ const MetalakeTree = props => {
   }
 
   const onExpand = (keys, { expanded, node }) => {
+    if (node.inUse === 'false') return
     if (expanded) {
       dispatch(setExpandedNodes(keys))
     } else {
@@ -158,6 +163,7 @@ const MetalakeTree = props => {
   }
 
   const onSelect = (keys, { selected, node }) => {
+    if (node.inUse === 'false') return
     if (!selected) {
       dispatch(setSelectedNodes([node.key]))
 
diff --git 
a/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js 
b/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
index aa836886a..4cb41e6fb 100644
--- a/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
+++ b/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
@@ -600,7 +600,9 @@ const CreateCatalogDialog = props => {
                                   name='key'
                                   label='Key'
                                   value={item.key}
-                                  disabled={item.required || item.disabled}
+                                  disabled={
+                                    item.required || item.disabled || 
(item.key === 'in-use' && type === 'update')
+                                  }
                                   onChange={event => handleFormChange({ index, 
event })}
                                   error={item.hasDuplicateKey || item.invalid 
|| !item.key.trim()}
                                   data-refer={`props-key-${index}`}
@@ -631,7 +633,7 @@ const CreateCatalogDialog = props => {
                                     label='Value'
                                     error={item.required && item.value === ''}
                                     value={item.value}
-                                    disabled={item.disabled}
+                                    disabled={item.disabled || (item.key === 
'in-use' && type === 'update')}
                                     onChange={event => handleFormChange({ 
index, event })}
                                     data-refer={`props-value-${index}`}
                                     data-prev-refer={`props-${item.key}`}
@@ -640,7 +642,7 @@ const CreateCatalogDialog = props => {
                                 )}
                               </Box>
 
-                              {!(item.required || item.disabled) ? (
+                              {!(item.required || item.disabled || (item.key 
=== 'in-use' && type === 'update')) ? (
                                 <Box sx={{ minWidth: 40 }}>
                                   <IconButton onClick={() => 
removeFields(index)}>
                                     <Icon icon='mdi:minus-circle-outline' />
diff --git 
a/web/web/src/app/metalakes/metalake/rightContent/tabsContent/tableView/TableView.js
 
b/web/web/src/app/metalakes/metalake/rightContent/tabsContent/tableView/TableView.js
index cf8cc3baf..964b7d6b8 100644
--- 
a/web/web/src/app/metalakes/metalake/rightContent/tabsContent/tableView/TableView.js
+++ 
b/web/web/src/app/metalakes/metalake/rightContent/tabsContent/tableView/TableView.js
@@ -25,7 +25,7 @@ import { useState, useEffect, Fragment } from 'react'
 
 import Link from 'next/link'
 
-import { styled, Box, Typography, IconButton, Stack } from '@mui/material'
+import { styled, Box, Typography, IconButton, Stack, Switch } from 
'@mui/material'
 import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
 import { DataGrid } from '@mui/x-data-grid'
 import {
@@ -44,10 +44,17 @@ import CreateSchemaDialog from '../../CreateSchemaDialog'
 import CreateFilesetDialog from '../../CreateFilesetDialog'
 
 import { useAppSelector, useAppDispatch } from '@/lib/hooks/useStore'
-import { deleteCatalog, deleteFileset, deleteSchema } from 
'@/lib/store/metalakes'
+import {
+  deleteCatalog,
+  deleteFileset,
+  deleteSchema,
+  resetExpandNode,
+  setCatalogInUse,
+  setIntoTreeNodes
+} from '@/lib/store/metalakes'
 
 import { to } from '@/lib/utils'
-import { getCatalogDetailsApi } from '@/lib/api/catalogs'
+import { getCatalogDetailsApi, switchInUseApi } from '@/lib/api/catalogs'
 import { getSchemaDetailsApi } from '@/lib/api/schemas'
 import { useSearchParams } from 'next/navigation'
 import { getFilesetDetailsApi } from '@/lib/api/filesets'
@@ -80,6 +87,8 @@ const TableView = () => {
   const type = searchParams.get('type') || ''
   const schema = searchParams.get('schema') || ''
 
+  const isCatalogList = paramsSize == 1 && searchParams.has('metalake')
+
   const isKafkaSchema =
     paramsSize == 3 &&
     searchParams.has('metalake') &&
@@ -237,26 +246,40 @@ const TableView = () => {
 
         return (
           <Box sx={{ display: 'flex', alignItems: 'center' }}>
-            <Tooltip title={row.comment} placement='right'>
-              <Typography
-                noWrap
-                {...(path
-                  ? {
-                      component: Link,
-                      href: path
-                    }
-                  : {})}
-                onClick={() => handleClickUrl(path)}
-                sx={{
-                  fontWeight: 400,
-                  color: 'primary.main',
-                  textDecoration: 'none',
-                  '&:hover': { color: 'primary.main', textDecoration: 
'underline' }
-                }}
-              >
-                {name}
-              </Typography>
+            <Tooltip title={row.comment} placement='left'>
+              {(isCatalogList && row.inUse === 'true') || !isCatalogList ? (
+                <Typography
+                  noWrap
+                  {...(path
+                    ? {
+                        component: Link,
+                        href: path
+                      }
+                    : {})}
+                  onClick={() => handleClickUrl(path)}
+                  sx={{
+                    fontWeight: 400,
+                    color: 'primary.main',
+                    textDecoration: 'none',
+                    '&:hover': { color: 'primary.main', textDecoration: 
'underline' }
+                  }}
+                >
+                  {name}
+                </Typography>
+              ) : (
+                <Typography>{name}</Typography>
+              )}
             </Tooltip>
+            {isCatalogList && (
+              <Tooltip title={row.inUse === 'true' ? 'In-use' : 'Not In-use'} 
placement='right'>
+                <Switch
+                  data-refer={`catalog-in-use-${name}`}
+                  checked={row.inUse === 'true'}
+                  onChange={(e, value) => handleChangeInUse(name, row.type, 
value)}
+                  size='small'
+                />
+              </Tooltip>
+            )}
           </Box>
         )
       }
@@ -564,6 +587,14 @@ const TableView = () => {
     }
   }
 
+  const handleChangeInUse = async (name, catalogType, isInUse) => {
+    const [err, res] = await to(switchInUseApi({ metalake, catalog: name, 
isInUse }))
+    if (err || !res) {
+      throw new Error(err)
+    }
+    dispatch(setCatalogInUse({ name, catalogType, metalake, isInUse }))
+  }
+
   const checkColumns = () => {
     if (
       (paramsSize == 1 && searchParams.has('metalake')) ||
diff --git a/web/web/src/components/ConfirmDeleteDialog.js 
b/web/web/src/components/ConfirmDeleteDialog.js
index 9cb38781b..b551a1fbf 100644
--- a/web/web/src/components/ConfirmDeleteDialog.js
+++ b/web/web/src/components/ConfirmDeleteDialog.js
@@ -22,7 +22,7 @@ import { Box, Button, Typography, Dialog, DialogContent, 
DialogActions } from '@
 import Icon from '@/components/Icon'
 
 const ConfirmDeleteDialog = props => {
-  const { open, setOpen, handleConfirmDeleteSubmit } = props
+  const { open, setOpen, confirmCacheData, handleConfirmDeleteSubmit } = props
 
   const handleClose = () => setOpen(false)
 
@@ -35,9 +35,16 @@ const ConfirmDeleteDialog = props => {
         >
           <Icon icon='tabler:alert-circle' fontSize='6rem' />
           <Typography variant='h4' className={'twc-mb-5 '} sx={{ color: 
'text.secondary' }}>
-            Confirm Delete?
+            Confirm Drop?
           </Typography>
-          <Typography>This action can not be reversed!</Typography>
+          {['metalake', 'catalog'].includes(confirmCacheData?.type) ? (
+            <Typography>
+              Make sure the {confirmCacheData.type} is not in-use, and all 
sub-entities in it are dropped. This action
+              can not be reversed!
+            </Typography>
+          ) : (
+            <Typography>This action can not be reversed!</Typography>
+          )}
         </Box>
       </DialogContent>
       <DialogActions className={'twc-justify-center twc-px-5 twc-pb-8'}>
@@ -47,7 +54,7 @@ const ConfirmDeleteDialog = props => {
           className={'twc-mr-2'}
           onClick={() => handleConfirmDeleteSubmit()}
         >
-          Delete
+          Drop
         </Button>
         <Button variant='outlined' color='secondary' onClick={() => 
handleClose()}>
           Cancel
diff --git a/web/web/src/lib/api/catalogs/index.js 
b/web/web/src/lib/api/catalogs/index.js
index 5272d50f7..8b0ca0e38 100644
--- a/web/web/src/lib/api/catalogs/index.js
+++ b/web/web/src/lib/api/catalogs/index.js
@@ -18,6 +18,7 @@
  */
 
 import { defHttp } from '@/lib/utils/axios'
+import { Api } from '@mui/icons-material'
 
 const Apis = {
   GET: ({ metalake }) => 
`/api/metalakes/${encodeURIComponent(metalake)}/catalogs?details=true`,
@@ -27,7 +28,9 @@ const Apis = {
   UPDATE: ({ metalake, catalog }) =>
     
`/api/metalakes/${encodeURIComponent(metalake)}/catalogs/${encodeURIComponent(catalog)}`,
   DELETE: ({ metalake, catalog }) =>
-    
`/api/metalakes/${encodeURIComponent(metalake)}/catalogs/${encodeURIComponent(catalog)}?force=true`
+    
`/api/metalakes/${encodeURIComponent(metalake)}/catalogs/${encodeURIComponent(catalog)}`,
+  UPDATEINUSE: ({ metalake, catalog }) =>
+    
`/api/metalakes/${encodeURIComponent(metalake)}/catalogs/${encodeURIComponent(catalog)}`
 }
 
 export const getCatalogsApi = params => {
@@ -61,3 +64,10 @@ export const deleteCatalogApi = ({ metalake, catalog }) => {
     url: `${Apis.DELETE({ metalake, catalog })}`
   })
 }
+
+export const switchInUseApi = ({ metalake, catalog, isInUse }) => {
+  return defHttp.patch({
+    url: `${Apis.UPDATEINUSE({ metalake, catalog })}`,
+    data: { inUse: isInUse }
+  })
+}
diff --git a/web/web/src/lib/api/metalakes/index.js 
b/web/web/src/lib/api/metalakes/index.js
index 5b7b14228..b1d7bb08a 100644
--- a/web/web/src/lib/api/metalakes/index.js
+++ b/web/web/src/lib/api/metalakes/index.js
@@ -23,7 +23,8 @@ const Apis = {
   GET: '/api/metalakes',
   CREATE: '/api/metalakes',
   DELETE: '/api/metalakes',
-  UPDATE: '/api/metalakes'
+  UPDATE: '/api/metalakes',
+  UPDATEINUSE: '/api/metalakes'
 }
 
 export const getMetalakesApi = () => {
@@ -47,7 +48,7 @@ export const createMetalakeApi = data => {
 
 export const deleteMetalakeApi = name => {
   return defHttp.delete({
-    url: `${Apis.DELETE}/${name}?force=true`
+    url: `${Apis.DELETE}/${name}`
   })
 }
 
@@ -63,3 +64,10 @@ export const getMetalakeDataApi = url => {
     url: `/api${url}`
   })
 }
+
+export const switchInUseApi = ({ name, isInUse }) => {
+  return defHttp.patch({
+    url: `${Apis.UPDATEINUSE}/${name}`,
+    data: { inUse: isInUse }
+  })
+}
diff --git a/web/web/src/lib/store/metalakes/index.js 
b/web/web/src/lib/store/metalakes/index.js
index 445d2838d..0499380af 100644
--- a/web/web/src/lib/store/metalakes/index.js
+++ b/web/web/src/lib/store/metalakes/index.js
@@ -295,6 +295,7 @@ export const fetchCatalogs = createAsyncThunk(
         path: `?${new URLSearchParams({ metalake, catalog: catalog.name, type: 
catalog.type }).toString()}`,
         type: catalog.type,
         provider: catalog.provider,
+        inUse: catalog.properties['in-use'],
         name: catalog.name,
         title: catalog.name,
         namespace: [metalake],
@@ -1131,6 +1132,34 @@ export const appMetalakesSlice = createSlice({
     removeCatalogFromTree(state, action) {
       state.metalakeTree = state.metalakeTree.filter(i => i.key !== 
action.payload)
     },
+    setCatalogInUse(state, action) {
+      const { name, catalogType, metalake, isInUse } = action.payload
+      for (let i = 0; i < state.catalogs.length; i++) {
+        if (state.catalogs[i].name === name) {
+          state.catalogs[i].inUse = isInUse + ''
+          state.tableData[i].inUse = isInUse + ''
+          const catalogItem = state.metalakeTree[i]
+          catalogItem.inUse = isInUse + ''
+          state.metalakeTree.splice(i, 1, catalogItem)
+          break
+        }
+      }
+      if (!isInUse) {
+        state.expandedNodes = state.expandedNodes.filter(key => 
!key.includes(name))
+        state.loadedNodes = state.loadedNodes.filter(key => 
!key.includes(name))
+        state.metalakeTree = updateTreeData(state.metalakeTree, 
`{{${metalake}}}{{${name}}}{{${catalogType}}}`, [])
+      } else {
+        state.metalakeTree = updateTreeData(state.metalakeTree, 
`{{${metalake}}}{{${name}}}{{${catalogType}}}`, null)
+      }
+    },
+    setMetalakeInUse(state, action) {
+      for (let i = 0; i < state.metalakes.length; i++) {
+        if (state.metalakes[i].name === action.payload.name) {
+          state.metalakes[i].properties['in-use'] = action.payload.isInUse + ''
+          break
+        }
+      }
+    },
     setTableProps(state, action) {
       state.tableProps = action.payload
     },
@@ -1315,6 +1344,8 @@ export const {
   setExpanded,
   setExpandedNodes,
   addCatalogToTree,
+  setCatalogInUse,
+  setMetalakeInUse,
   removeCatalogFromTree,
   setTableProps
 } = appMetalakesSlice.actions
diff --git a/web/web/src/lib/utils/axios/Axios.js 
b/web/web/src/lib/utils/axios/Axios.js
index 92411b012..652945b53 100644
--- a/web/web/src/lib/utils/axios/Axios.js
+++ b/web/web/src/lib/utils/axios/Axios.js
@@ -263,6 +263,16 @@ class NextAxios {
     return this.request({ ...config, method: 'PUT' }, options)
   }
 
+  /**
+   * @template T
+   * @param {AxiosRequestConfig} config
+   * @param {RequestOptions} [options]
+   * @returns {Promise<T>}
+   */
+  patch(config, options) {
+    return this.request({ ...config, method: 'PATCH' }, options)
+  }
+
   /**
    * @template T
    * @param {AxiosRequestConfig} config

Reply via email to