Skip to content

Commit

Permalink
feat: move connection delete action to connection list
Browse files Browse the repository at this point in the history
  • Loading branch information
mintsweet committed Aug 19, 2024
1 parent 5de4908 commit 57d272d
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 140 deletions.
159 changes: 128 additions & 31 deletions config-ui/src/plugins/components/connection-list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,33 +52,71 @@ 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]);

const {
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
Expand All @@ -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>
</>
),
},
Expand All @@ -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>
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
112 changes: 4 additions & 108 deletions config-ui/src/routes/connection/connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
*/

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';

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,
Expand All @@ -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);
Expand All @@ -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],
Expand Down Expand Up @@ -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');
};
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 57d272d

Please sign in to comment.