This is an automated email from the ASF dual-hosted git repository.
klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new 6871e158c feat: move connection delete action to connection list
(#7913)
6871e158c is described below
commit 6871e158c76568c7d4c6861560414e1e4053a274
Author: 青湛 <[email protected]>
AuthorDate: Mon Aug 19 19:56:53 2024 +1200
feat: move connection delete action to connection list (#7913)
---
.../plugins/components/connection-list/index.tsx | 159 +++++++++++++++++----
.../plugins/components/connection-status/index.tsx | 2 +-
config-ui/src/routes/connection/connection.tsx | 112 +--------------
3 files changed, 133 insertions(+), 140 deletions(-)
diff --git a/config-ui/src/plugins/components/connection-list/index.tsx
b/config-ui/src/plugins/components/connection-list/index.tsx
index e0985b1d1..981705833 100644
--- a/config-ui/src/plugins/components/connection-list/index.tsx
+++ b/config-ui/src/plugins/components/connection-list/index.tsx
@@ -18,15 +18,17 @@
import { useState, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
-import { EyeOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
-import { theme, Table, Button, Modal } from 'antd';
+import { EyeOutlined, EditOutlined, DeleteOutlined, PlusOutlined } from
'@ant-design/icons';
+import { theme, Table, Button, Modal, message } from 'antd';
import styled from 'styled-components';
-import { selectConnections } from '@/features/connections';
+import { selectConnections, removeConnection } from '@/features/connections';
+import { Message } from '@/components';
import { PATHS } from '@/config';
-import { useAppSelector } from '@/hooks';
+import { useAppDispatch, useAppSelector } from '@/hooks';
import { getPluginConfig, ConnectionStatus, ConnectionForm } from '@/plugins';
import { WebHookConnection } from '@/plugins/register/webhook';
+import { operator } from '@/utils';
const ModalTitle = styled.div`
display: flex;
@@ -50,8 +52,11 @@ interface Props {
}
export const ConnectionList = ({ plugin, onCreate }: Props) => {
- const [open, setOpen] = useState(false);
+ const [modalType, setModalType] = useState<'update' | 'delete' |
'deleteFailed'>();
const [connectionId, setConnectionId] = useState<ID>();
+ const [operating, setOperating] = useState(false);
+ const [conflict, setConflict] = useState<string[]>([]);
+ const [errorMsg, setErrorMsg] = useState('');
const pluginConfig = useMemo(() => getPluginConfig(plugin), [plugin]);
@@ -59,24 +64,59 @@ export const ConnectionList = ({ plugin, onCreate }: Props)
=> {
token: { colorPrimary },
} = theme.useToken();
+ const dispatch = useAppDispatch();
const connections = useAppSelector((state) => selectConnections(state,
plugin));
const navigate = useNavigate();
- if (plugin === 'webhook') {
- return <WebHookConnection />;
- }
-
- const handleShowForm = (id: ID) => {
- setOpen(true);
+ const handleShowModal = (type: 'update' | 'delete', id: ID) => {
+ setModalType(type);
setConnectionId(id);
};
- const hanldeHideForm = () => {
- setOpen(false);
+ const hanldeHideModal = () => {
+ setModalType(undefined);
setConnectionId(undefined);
};
+ const handleDelete = async () => {
+ const [, res] = await operator(
+ async () => {
+ try {
+ await dispatch(removeConnection({ plugin, connectionId })).unwrap();
+ return { status: 'success' };
+ } catch (err: any) {
+ const { status, data, message } = err;
+ return {
+ status: status === 409 ? 'conflict' : 'error',
+ conflict: data ? [...data.projects, ...data.blueprints] : [],
+ message,
+ };
+ }
+ },
+ {
+ setOperating,
+ hideToast: true,
+ },
+ );
+
+ if (res.status === 'success') {
+ message.success('Delete Connection Successful.');
+ hanldeHideModal();
+ } else if (res.status === 'conflict') {
+ setModalType('deleteFailed');
+ setConflict(res.conflict);
+ setErrorMsg(res.message);
+ } else {
+ message.error('Operation failed.');
+ hanldeHideModal();
+ }
+ };
+
+ if (plugin === 'webhook') {
+ return <WebHookConnection />;
+ }
+
return (
<>
<Table
@@ -97,15 +137,18 @@ export const ConnectionList = ({ plugin, onCreate }:
Props) => {
{
title: '',
key: 'link',
- width: 200,
+ width: 300,
render: (_, { plugin, id }) => (
<>
<Button type="link" icon={<EyeOutlined />} onClick={() =>
navigate(PATHS.CONNECTION(plugin, id))}>
Details
</Button>
- <Button type="link" icon={<EditOutlined />} onClick={() =>
handleShowForm(id)}>
+ <Button type="link" icon={<EditOutlined />} onClick={() =>
handleShowModal('update', id)}>
Edit
</Button>
+ <Button type="link" danger icon={<DeleteOutlined />}
onClick={() => handleShowModal('delete', id)}>
+ Delete
+ </Button>
</>
),
},
@@ -116,22 +159,76 @@ export const ConnectionList = ({ plugin, onCreate }:
Props) => {
<Button style={{ marginTop: 16 }} type="primary" icon={<PlusOutlined />}
onClick={onCreate}>
Create a New Connection
</Button>
- <Modal
- destroyOnClose
- open={open}
- width={820}
- centered
- title={
- <ModalTitle>
- <span className="icon">{pluginConfig.icon({ color: colorPrimary
})}</span>
- <span className="name">Manage Connections:
{pluginConfig.name}</span>
- </ModalTitle>
- }
- footer={null}
- onCancel={hanldeHideForm}
- >
- <ConnectionForm plugin={plugin} connectionId={connectionId}
onSuccess={hanldeHideForm} />
- </Modal>
+ {modalType === 'update' && (
+ <Modal
+ destroyOnClose
+ open
+ width={820}
+ centered
+ title={
+ <ModalTitle>
+ <span className="icon">{pluginConfig.icon({ color: colorPrimary
})}</span>
+ <span className="name">Manage Connections:
{pluginConfig.name}</span>
+ </ModalTitle>
+ }
+ footer={null}
+ onCancel={hanldeHideModal}
+ >
+ <ConnectionForm plugin={plugin} connectionId={connectionId}
onSuccess={hanldeHideModal} />
+ </Modal>
+ )}
+ {modalType === 'delete' && (
+ <Modal
+ open
+ width={820}
+ centered
+ title="Would you like to delete this Data Connection?"
+ okText="Confirm"
+ okButtonProps={{
+ loading: operating,
+ }}
+ onCancel={hanldeHideModal}
+ onOk={handleDelete}
+ >
+ <Message
+ content=" This operation cannot be undone. Deleting a Data
Connection will delete all data that have been collected
+ in this Connection."
+ />
+ </Modal>
+ )}
+ {modalType === 'deleteFailed' && (
+ <Modal
+ open
+ width={820}
+ centered
+ style={{ width: 820 }}
+ title="This Data Connection can not be deleted."
+ cancelButtonProps={{
+ style: {
+ display: 'none',
+ },
+ }}
+ onCancel={hanldeHideModal}
+ onOk={hanldeHideModal}
+ >
+ {!conflict.length ? (
+ <Message content={errorMsg} />
+ ) : (
+ <>
+ <Message
+ content={`This Data Connection can not be deleted because it
has been used in the following projects/blueprints:`}
+ />
+ <ul style={{ paddingLeft: 36 }}>
+ {conflict.map((it) => (
+ <li key={it} style={{ color: colorPrimary }}>
+ {it}
+ </li>
+ ))}
+ </ul>
+ </>
+ )}
+ </Modal>
+ )}
</>
);
};
diff --git a/config-ui/src/plugins/components/connection-status/index.tsx
b/config-ui/src/plugins/components/connection-status/index.tsx
index eb4c2e424..4c8aa3b49 100644
--- a/config-ui/src/plugins/components/connection-status/index.tsx
+++ b/config-ui/src/plugins/components/connection-status/index.tsx
@@ -54,7 +54,7 @@ export const ConnectionStatus = ({ connection }: Props) => {
const dispatch = useAppDispatch();
- const handleTest = () => operator(() =>
dispatch(testConnection(connection)).unwrap());
+ const handleTest = () => operator(() =>
dispatch(testConnection(connection)).unwrap(), { hideToast: true });
return (
<Wrapper>
diff --git a/config-ui/src/routes/connection/connection.tsx
b/config-ui/src/routes/connection/connection.tsx
index 3652c26b3..ef7431914 100644
--- a/config-ui/src/routes/connection/connection.tsx
+++ b/config-ui/src/routes/connection/connection.tsx
@@ -17,7 +17,7 @@
*/
import { useState, useMemo } from 'react';
-import { useParams, useNavigate, Link } from 'react-router-dom';
+import { useParams, Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { DeleteOutlined, PlusOutlined, LinkOutlined, ClearOutlined } from
'@ant-design/icons';
import { theme, Space, Table, Button, Modal, message } from 'antd';
@@ -25,8 +25,8 @@ import { theme, Space, Table, Button, Modal, message } from
'antd';
import API from '@/api';
import { PageHeader, Message, IconButton } from '@/components';
import { PATHS } from '@/config';
-import { useAppDispatch, useAppSelector } from '@/hooks';
-import { selectConnection, removeConnection } from '@/features';
+import { useAppSelector } from '@/hooks';
+import { selectConnection } from '@/features';
import { useRefreshData } from '@/hooks';
import {
ConnectionStatus,
@@ -45,13 +45,7 @@ const brandName = import.meta.env.DEVLAKE_BRAND_NAME ??
'DevLake';
export const Connection = () => {
const [type, setType] = useState<
- | 'deleteConnection'
- | 'createDataScope'
- | 'clearDataScope'
- | 'deleteDataScope'
- | 'associateScopeConfig'
- | 'deleteConnectionFailed'
- | 'deleteDataScopeFailed'
+ 'createDataScope' | 'clearDataScope' | 'deleteDataScope' |
'associateScopeConfig' | 'deleteDataScopeFailed'
>();
const [operating, setOperating] = useState(false);
const [version, setVersion] = useState(1);
@@ -69,11 +63,8 @@ export const Connection = () => {
token: { colorPrimary },
} = theme.useToken();
- const dispatch = useAppDispatch();
const connection = useAppSelector((state) => selectConnection(state,
`${plugin}-${connectionId}`)) as IConnection;
- const navigate = useNavigate();
-
const { ready, data } = useRefreshData(
() => API.scope.list(plugin, connectionId, { page, pageSize, blueprints:
true }),
[version, page, pageSize],
@@ -101,44 +92,6 @@ export const Connection = () => {
setType(undefined);
};
- const handleShowDeleteDialog = () => {
- setType('deleteConnection');
- };
-
- const handleDelete = async () => {
- const [, res] = await operator(
- async () => {
- try {
- await dispatch(removeConnection({ plugin, connectionId })).unwrap();
- return { status: 'success' };
- } catch (err: any) {
- const { status, data, message } = err;
- return {
- status: status === 409 ? 'conflict' : 'error',
- conflict: data ? [...data.projects, ...data.blueprints] : [],
- message,
- };
- }
- },
- {
- setOperating,
- hideToast: true,
- },
- );
-
- if (res.status === 'success') {
- message.success('Delete Connection Successful.');
- navigate(PATHS.CONNECTIONS());
- } else if (res.status === 'conflict') {
- setType('deleteConnectionFailed');
- setConflict(res.conflict);
- setErrorMsg(res.message);
- } else {
- message.error('Operation failed.');
- handleHideDialog();
- }
- };
-
const handleShowCreateDataScopeDialog = () => {
setType('createDataScope');
};
@@ -238,11 +191,6 @@ export const Connection = () => {
{ name: 'Connections', path: PATHS.CONNECTIONS() },
{ name, path: '' },
]}
- extra={
- <Button type="primary" danger icon={<DeleteOutlined />}
onClick={handleShowDeleteDialog}>
- Delete Connection
- </Button>
- }
>
<Helmet>
<title>
@@ -358,25 +306,6 @@ export const Connection = () => {
}}
/>
</Space>
- {type === 'deleteConnection' && (
- <Modal
- open
- width={820}
- centered
- title="Would you like to delete this Data Connection?"
- okText="Confirm"
- okButtonProps={{
- loading: operating,
- }}
- onCancel={handleHideDialog}
- onOk={handleDelete}
- >
- <Message
- content=" This operation cannot be undone. Deleting a Data
Connection will delete all data that have been collected
- in this Connection."
- />
- </Modal>
- )}
{type === 'createDataScope' && (
<Modal
getContainer={false}
@@ -459,39 +388,6 @@ export const Connection = () => {
/>
</Modal>
)}
- {type === 'deleteConnectionFailed' && (
- <Modal
- open
- width={820}
- centered
- style={{ width: 820 }}
- title="This Data Connection can not be deleted."
- cancelButtonProps={{
- style: {
- display: 'none',
- },
- }}
- onCancel={handleHideDialog}
- onOk={handleHideDialog}
- >
- {!conflict.length ? (
- <Message content={errorMsg} />
- ) : (
- <>
- <Message
- content={`This Data Connection can not be deleted because it
has been used in the following projects/blueprints:`}
- />
- <ul style={{ paddingLeft: 36 }}>
- {conflict.map((it) => (
- <li key={it} style={{ color: colorPrimary }}>
- {it}
- </li>
- ))}
- </ul>
- </>
- )}
- </Modal>
- )}
{type === 'deleteDataScopeFailed' && (
<Modal
open