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